[
  {
    "path": ".eslintrc",
    "content": "{\n  \"env\": {\n    \"es6\": true,\n    \"node\": true,\n  },\n  \"rules\": {\n    \"no-console\": \"off\",\n    \"no-trailing-spaces\": \"error\"\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 2017,\n    \"sourceType\": \"module\"\n  },\n  \"extends\": \"eslint:recommended\"\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.idea\n*.pickle\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nsudo: false\nnode_js:\n  - \"node\"\nbefore_install:\n  - pyenv global 3.6\ninstall:\n  - npm install\nscript:\n  - npm test\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n# How to contribute\n\nWelcome! We are super happy that you intend to contribute to the javascript-call-graph! This is a great place to start.\n\n#### If you find a bug\n\n* If you can fix it, submit a PR.\n* If not, open up an issue and include any information that could help others reproduce and fix.\n\n#### If you have a feature proposal or want to contribute\n\n* Open up an issue for discussion.\n* Contribute a PR.\n* Respond to code review\n* Watch the PR be merged, and bathe in a job well done :icecream: :+1: :v: :palm_tree:.\n\n## How to create a Pull Request\n\n* First you should **fork** this repository (hit the fork button)\n* **Clone** your forked repository\n* **Create a branch** for you new feature\n* **Commit your changes** to your branch\n* **Keep your fork synced** with the original repository if needed. See [Keeping the fork up to date](#keeping-the-fork-up-to-date) section for further details.\n* When you finished your work:\n\t* **Open a Pull Request** in the original repository and set master as base and your newly created branch as head. Please fill the description field for letting the others know what the contribution is about.\n\t* If your changes seem good for the maintainers they will accept your pull request and merge your commits into the original repository\n\n## Keeping the fork up to date\n\nIt is an optional step. It is recommended when you are working on a larger feature or a complex bug (not a tiny quick fix).\nFollowing the steps below ensures to track the original fork which is usually called __upstream__.\nFirst add the original repository as a remote:\n\n```\n# Add 'upstream' repo to list of remotes\ngit remote add upstream https://github.com/UPSTREAM-USER/ORIGINAL-PROJECT.git\n# Verify the new remote named 'upstream'\ngit remote -v\n```\n\nTo update your fork to the latest version you have to fetch the changes from the upstream:\n  \n```\n# Fetch from upstream remote\ngit fetch upstream\n# View all branches, including those from upstream\ngit branch -va\n```\n\nNow, checkout your own master branch and merge the upstream repo's master branch:\n\n```\n# Checkout your master branch and merge upstream\ngit checkout master\ngit merge upstream/master\n```\n\nNow your master is up to date with the remote upstream repository. Your feature branch should be also updated. For this purpose you can use a rebase command:\n  \n```\ngit checkout newfeature\n# Updates origin/master\ngit fetch origin\n# Rebases current branch onto origin/master\ngit rebase origin/master\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "Eclipse Public License - v 2.0\n\n    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n    PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION\n    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.\n\n1. DEFINITIONS\n\n\"Contribution\" means:\n\n  a) in the case of the initial Contributor, the initial content\n     Distributed under this Agreement, and\n\n  b) in the case of each subsequent Contributor:\n     i) changes to the Program, and\n     ii) additions to the Program;\n  where such changes and/or additions to the Program originate from\n  and are Distributed by that particular Contributor. A Contribution\n  \"originates\" from a Contributor if it was added to the Program by\n  such Contributor itself or anyone acting on such Contributor's behalf.\n  Contributions do not include changes or additions to the Program that\n  are not Modified Works.\n\n\"Contributor\" means any person or entity that Distributes the Program.\n\n\"Licensed Patents\" mean patent claims licensable by a Contributor which\nare necessarily infringed by the use or sale of its Contribution alone\nor when combined with the Program.\n\n\"Program\" means the Contributions Distributed in accordance with this\nAgreement.\n\n\"Recipient\" means anyone who receives the Program under this Agreement\nor any Secondary License (as applicable), including Contributors.\n\n\"Derivative Works\" shall mean any work, whether in Source Code or other\nform, that is based on (or derived from) the Program and for which the\neditorial revisions, annotations, elaborations, or other modifications\nrepresent, as a whole, an original work of authorship.\n\n\"Modified Works\" shall mean any work in Source Code or other form that\nresults from an addition to, deletion from, or modification of the\ncontents of the Program, including, for purposes of clarity any new file\nin Source Code form that contains any contents of the Program. Modified\nWorks shall not include works that contain only declarations,\ninterfaces, types, classes, structures, or files of the Program solely\nin each case in order to link to, bind by name, or subclass the Program\nor Modified Works thereof.\n\n\"Distribute\" means the acts of a) distributing or b) making available\nin any manner that enables the transfer of a copy.\n\n\"Source Code\" means the form of a Program preferred for making\nmodifications, including but not limited to software source code,\ndocumentation source, and configuration files.\n\n\"Secondary License\" means either the GNU General Public License,\nVersion 2.0, or any later versions of that license, including any\nexceptions or additional permissions as identified by the initial\nContributor.\n\n2. GRANT OF RIGHTS\n\n  a) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free copyright\n  license to reproduce, prepare Derivative Works of, publicly display,\n  publicly perform, Distribute and sublicense the Contribution of such\n  Contributor, if any, and such Derivative Works.\n\n  b) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free patent\n  license under Licensed Patents to make, use, sell, offer to sell,\n  import and otherwise transfer the Contribution of such Contributor,\n  if any, in Source Code or other form. This patent license shall\n  apply to the combination of the Contribution and the Program if, at\n  the time the Contribution is added by the Contributor, such addition\n  of the Contribution causes such combination to be covered by the\n  Licensed Patents. The patent license shall not apply to any other\n  combinations which include the Contribution. No hardware per se is\n  licensed hereunder.\n\n  c) Recipient understands that although each Contributor grants the\n  licenses to its Contributions set forth herein, no assurances are\n  provided by any Contributor that the Program does not infringe the\n  patent or other intellectual property rights of any other entity.\n  Each Contributor disclaims any liability to Recipient for claims\n  brought by any other entity based on infringement of intellectual\n  property rights or otherwise. As a condition to exercising the\n  rights and licenses granted hereunder, each Recipient hereby\n  assumes sole responsibility to secure any other intellectual\n  property rights needed, if any. For example, if a third party\n  patent license is required to allow Recipient to Distribute the\n  Program, it is Recipient's responsibility to acquire that license\n  before distributing the Program.\n\n  d) Each Contributor represents that to its knowledge it has\n  sufficient copyright rights in its Contribution, if any, to grant\n  the copyright license set forth in this Agreement.\n\n  e) Notwithstanding the terms of any Secondary License, no\n  Contributor makes additional grants to any Recipient (other than\n  those set forth in this Agreement) as a result of such Recipient's\n  receipt of the Program under the terms of a Secondary License\n  (if permitted under the terms of Section 3).\n\n3. REQUIREMENTS\n\n3.1 If a Contributor Distributes the Program in any form, then:\n\n  a) the Program must also be made available as Source Code, in\n  accordance with section 3.2, and the Contributor must accompany\n  the Program with a statement that the Source Code for the Program\n  is available under this Agreement, and informs Recipients how to\n  obtain it in a reasonable manner on or through a medium customarily\n  used for software exchange; and\n\n  b) the Contributor may Distribute the Program under a license\n  different than this Agreement, provided that such license:\n     i) effectively disclaims on behalf of all other Contributors all\n     warranties and conditions, express and implied, including\n     warranties or conditions of title and non-infringement, and\n     implied warranties or conditions of merchantability and fitness\n     for a particular purpose;\n\n     ii) effectively excludes on behalf of all other Contributors all\n     liability for damages, including direct, indirect, special,\n     incidental and consequential damages, such as lost profits;\n\n     iii) does not attempt to limit or alter the recipients' rights\n     in the Source Code under section 3.2; and\n\n     iv) requires any subsequent distribution of the Program by any\n     party to be under a license that satisfies the requirements\n     of this section 3.\n\n3.2 When the Program is Distributed as Source Code:\n\n  a) it must be made available under this Agreement, or if the\n  Program (i) is combined with other material in a separate file or\n  files made available under a Secondary License, and (ii) the initial\n  Contributor attached to the Source Code the notice described in\n  Exhibit A of this Agreement, then the Program may be made available\n  under the terms of such Secondary Licenses, and\n\n  b) a copy of this Agreement must be included with each copy of\n  the Program.\n\n3.3 Contributors may not remove or alter any copyright, patent,\ntrademark, attribution notices, disclaimers of warranty, or limitations\nof liability (\"notices\") contained within the Program from any copy of\nthe Program which they Distribute, provided that Contributors may add\ntheir own appropriate notices.\n\n4. COMMERCIAL DISTRIBUTION\n\nCommercial distributors of software may accept certain responsibilities\nwith respect to end users, business partners and the like. While this\nlicense is intended to facilitate the commercial use of the Program,\nthe Contributor who includes the Program in a commercial product\noffering should do so in a manner which does not create potential\nliability for other Contributors. Therefore, if a Contributor includes\nthe Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and indemnify every\nother Contributor (\"Indemnified Contributor\") against any losses,\ndamages and costs (collectively \"Losses\") arising from claims, lawsuits\nand other legal actions brought by a third party against the Indemnified\nContributor to the extent caused by the acts or omissions of such\nCommercial Contributor in connection with its distribution of the Program\nin a commercial product offering. The obligations in this section do not\napply to any claims or Losses relating to any actual or alleged\nintellectual property infringement. In order to qualify, an Indemnified\nContributor must: a) promptly notify the Commercial Contributor in\nwriting of such claim, and b) allow the Commercial Contributor to control,\nand cooperate with the Commercial Contributor in, the defense and any\nrelated settlement negotiations. The Indemnified Contributor may\nparticipate in any such claim at its own expense.\n\nFor example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those performance\nclaims and warranties, and if a court requires any other Contributor to\npay any damages as a result, the Commercial Contributor must pay\nthose damages.\n\n5. NO WARRANTY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN \"AS IS\"\nBASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR\nIMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF\nTITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR\nPURPOSE. Each Recipient is solely responsible for determining the\nappropriateness of using and distributing the Program and assumes all\nrisks associated with its exercise of rights under this Agreement,\nincluding but not limited to the risks and costs of program errors,\ncompliance with applicable laws, damage to or loss of data, programs\nor equipment, and unavailability or interruption of operations.\n\n6. DISCLAIMER OF LIABILITY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS\nSHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST\nPROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE\nEXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n7. GENERAL\n\nIf any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further\naction by the parties hereto, such provision shall be reformed to the\nminimum extent necessary to make such provision valid and enforceable.\n\nIf Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other software\nor hardware) infringes such Recipient's patent(s), then such Recipient's\nrights granted under Section 2(b) shall terminate as of the date such\nlitigation is filed.\n\nAll Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of\ntime after becoming aware of such noncompliance. If all Recipient's\nrights under this Agreement terminate, Recipient agrees to cease use\nand distribution of the Program as soon as reasonably practicable.\nHowever, Recipient's obligations under this Agreement and any licenses\ngranted by Recipient relating to the Program shall continue and survive.\n\nEveryone is permitted to copy and distribute copies of this Agreement,\nbut in order to avoid inconsistency the Agreement is copyrighted and\nmay only be modified in the following manner. The Agreement Steward\nreserves the right to publish new versions (including revisions) of\nthis Agreement from time to time. No one other than the Agreement\nSteward has the right to modify this Agreement. The Eclipse Foundation\nis the initial Agreement Steward. The Eclipse Foundation may assign the\nresponsibility to serve as the Agreement Steward to a suitable separate\nentity. Each new version of the Agreement will be given a distinguishing\nversion number. The Program (including Contributions) may always be\nDistributed subject to the version of the Agreement under which it was\nreceived. In addition, after a new version of the Agreement is published,\nContributor may elect to Distribute the Program (including its\nContributions) under the new version.\n\nExcept as expressly stated in Sections 2(a) and 2(b) above, Recipient\nreceives no rights or licenses to the intellectual property of any\nContributor under this Agreement, whether expressly, by implication,\nestoppel or otherwise. All rights in the Program not expressly granted\nunder this Agreement are reserved. Nothing in this Agreement is intended\nto be enforceable by any entity that is not a Contributor or Recipient.\nNo third-party beneficiary rights are created under this Agreement.\n\nExhibit A - Form of Secondary Licenses Notice\n\n\"This Source Code may also be made available under the following \nSecondary Licenses when the conditions for such availability set forth \nin the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\nversion(s), and exceptions or additional permissions here}.\"\n\n  Simply including a copy of this Agreement, including this Exhibit A\n  is not sufficient to license the Source Code under Secondary Licenses.\n\n  If it is not possible or desirable to put the notice in a particular\n  file, then You may include the notice in a location (such as a LICENSE\n  file in a relevant directory) where a recipient would be likely to\n  look for such a notice.\n\n  You may add additional accurate notices of copyright ownership.\n"
  },
  {
    "path": "README.md",
    "content": "# Field-based Call Graph Construction for JavaScript #\n\n\n[![Build Status](https://travis-ci.org/Persper/js-callgraph.svg?branch=master)](https://travis-ci.org/Persper/js-callgraph)\n[![NPM version](https://img.shields.io/badge/npm-v1.3.2-blue.svg)](https://www.npmjs.com/package/@persper/js-callgraph)\n[![License](https://img.shields.io/badge/license-EPL--2.0-green.svg)](https://www.eclipse.org/legal/epl-2.0/)\n\nThis project implements a field-based call graph construction algorithm for JavaScript as described in\n\n> A. Feldthaus, M. Schäfer, M. Sridharan, J. Dolby, F. Tip. Efficient Construction of Approximate Call Graphs for JavaScript IDE Services. In *ICSE*, 2013.\n\nThis repo builds upon [Max Schaefer](https://github.com/xiemaisi)'s original [acg.js](https://github.com/xiemaisi/acg.js) and adds\n\n* ES6 Support\n\t* Arrow functions\n\t* Destructuring assignments\n\t* Classes\n\t* Enhanced object literals\n\t* Rest/Spread operator\n* Module Support\n\t* ES6/CommonJS/AMD\n* More sophisticated scoping\n* Partial update to a large call graph\n* Unified JSON format representing a call graph\n* More flexible CLI\n\t* Take directory parameter\n\t* Support filtering files by regex\n* Vue.js support (.vue files)\n* More tests\n\n## Get Started (CLI)\n```\nnpm install -g @persper/js-callgraph\njs-callgraph -h # for a list of command line arguments\n\n# Running on simple input scripts\njs-callgraph --cg input-scripts/simple-scripts/functioncall-arithmetic.js\n\n# Running on a whole directory\njs-callgraph --cg input-scripts/fullcalendar/\n\n# Running on mixed input\njs-callgraph --cg input-scripts/fullcalendar/fullcalendar/ input-scripts/fullcalendar/lib/jquery-2.1.0.js\n\n# Saving the result into a file\njs-callgraph --cg input-scripts/simple-scripts/functioncall-arithmetic.js --output filename.json\n\n# Running on a whole directory with filtering\njs-callgraph --cg input-scripts/fullcalendar/ --filter filename.filter\n```\n\nFor an example of the output json, please see [here](#unified-json-format).\nFor an example of filtering file, please see [here](#filter-file-format).\n\n## Programming Interface\n\n```\nconst JCG = require(\"./src/runner\");\nargs = { ... };\nJCG.setArgs(args);                                # Optional, specify a list of arguments\nJCG.setFiles(['file.js', 'directory/']);          # List of files or directories to analyze\nJCG.setFilter(['-test[^\\.]*.js', '+test576.js']); # Optional, please see \"Filter file format\" section for details\nJCG.setConsoleOutput(true);                       # Optional, the console output can be turned off.\nJCG.build();                                      # build returns the call graph as a JSON object, please see \"Unified JSON Format\" section\n```\n\n## Running Tests\nTo run the testing framework run:\n```\nnpm test\n```\nTo install the git hooks to run tests automatically pre-commit run:\n```\nscripts/install-hooks\n```\n## Structure\n\nThe call graph constructor can be run in two basic modes (selected using the `--strategy` flag to `javascript-call-graph`), *pessimistic* and *optimistic*, which differ in how interprocedural flows are handled. In the basic pessimistic approach (strategy `NONE`), interprocedural flow is not tracked at all; a slight refinement is strategy `ONESHOT`, where interprocedural flow is tracked only for one-shot closures that are invoked immediatel. The optimistic approach (strategy `DEMAND`) performs interprocedural propagation along edges that may ultimately end at a call site (and are thus interesting for call graph construction). Full interprocedural propagation (strategy `FULL`) is not implemented yet.\n\nAll strategies use the same intraprocedural flow graph, in which properties are only identified by name; thus, like-named properties of different objects are conflated; this can lead to imprecise call graphs. Dynamic property reads and writes are ignored, as are reflective calls using `call` and `apply`; thus, the call graphs are intrinsically incomplete.\n\nModule `flowgraph.js` contains the code for extracting an intraprocedural flow graph from an [Esprima](esprima.org) AST annotated with name bindings for local variables (see `bindings.js`, which uses `symtab.js` and `astutil.js`).\n\nModules `pessimistic.js` and `semioptimistic.js` implement the pessimistic and optimistic call graph builders, respectively. They both use `flowgraph.js` to build an intraprocedural flow graph, and then add some edges corresponding to interprocedural flow. Both use module `callgraph.js` for extracting a call graph from a given flow graph, by collecting, for every call site, all functions that can flow into the callee position. Both use module `natives.js` to add flow edges modelling well-known standard library functions.\n\nThe remaining modules define key data structures, in several variants.\n\nModule `graph.js` implements graphs using adjacency sets, using sets of numbers as implemented by `numset.js`. The latter includes either `olist.js` to implement sets as ordered lists of numbers, or `bitset.js` to use bitsets (with disappointing performance, so we use ordered lists by default).\n\nModules `dftc.js`, `heuristictc.js` and `nuutila.js` implement several transitive closure algorithms used by `callgraph.js`. By default, we use `dftc.js` which uses a simple, depth first-search based algorithm. `heuristictc.js` does something even simpler, which is very fast but unsound. Finally, `nuutila.js` implements Nuutila's algorithm for transitive closure, which for our graphs is usually slower than the depth first-based ones.\n\n## Unified JSON Format\n\n```\n[ # The calls are represented with a list of objects. Each call is an object in this list.\n  {\n    \"source\": { # The source object represents the start point of a call (the caller node)\n      \"label\": \"global\",\n      \"file\": \"...\\\\input-scripts\\\\simple-scripts\\\\functioncall-arithmetic.js\",\n      \"start\": { # The start point of the source with row-column based position.\n        \"row\": 7,\n        \"column\": 4\n      },\n      \"end\": { # The end point of the source node with row-column based position.\n        \"row\": 7,\n        \"column\": 8\n      },\n      \"range\": { # The position of the source node in index-based representation.\n        \"start\": 59,\n        \"end\": 63\n      }\n    },\n    \"target\": { # The target object represents the end point of a call (this node is called by the source)\n      \"label\": \"f\",\n      \"file\": \"...\\\\input-scripts\\\\simple-scripts\\\\functioncall-arithmetic.js\",\n      \"start\": { # The start point of the target node with row-column based position..\n        \"row\": 3,\n        \"column\": 0\n      },\n      \"end\": { # The end point of the target node with row-column based position.\n        \"row\": 5,\n        \"column\": 1\n      },\n      \"range\": { # The position of the target node in index-based representation.\n        \"start\": 14,\n        \"end\": 51\n      }\n    }\n  }\n]\n```\n\n## Filter file format\n\nAny valid regular expression can be specified in the filter file. The order of the including and excluding lines are important since they are processed sequentially.\n\nThe first character of each line represents the type of the filtering:\n```\n# Comment line\n- Exclude\n+ Include\n```\n\nAn example for filtering:\n\n```\n# Filter out all source files starting with \"test\":\n-test[^\\.]*.js\n# But test576.js is needed:\n+test576.js\n# Furthermore, files beginning with \"test1742\" are also needed:\n+test1742[^\\.]*.js\n# Finally, test1742_b.js is not needed:\n-test1742_b.js\n```\n\n## List of arguments\n\n```\n-h         : List of command line arguments\n--fg       : print flow graph\n--cg       : print call graph\n--time     : print timings\n--strategy : interprocedural propagation strategy; one of NONE, ONESHOT (default), DEMAND, and FULL (not yet implemented)\n--countCB  : Counts the number of callbacks.\n--reqJs    : Make a RequireJS dependency graph.\n--output   : The output file name into which the result JSON should be saved. (extension: .json)\n--filter   : Path to the filter file.\n```\n\n# Contributing\n\nLooking to contribute something? [Here's how you can help](/CONTRIBUTING.md).\n\n# License #\n\nThis code is licensed under the [Eclipse Public License (v2.0)](http://www.eclipse.org/legal/epl-2.0), a copy of which is included in this repository in file `LICENSE`.\n"
  },
  {
    "path": "index.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\nconst JCG = require(\"./src/runner\");\n\nexports.setArgs = JCG.setArgs;\nexports.setFiles = JCG.setFiles;\nexports.setFilter = JCG.setFilter;\nexports.setConsoleOutput = JCG.setConsoleOutput;\nexports.build = JCG.build;\n"
  },
  {
    "path": "input-scripts/coolclock/coolclock.js",
    "content": "/**\n * CoolClock 2.1.4\n * Copyright 2010, Simon Baird\n * Released under the BSD License.\n *\n * Display an analog clock using canvas.\n * http://randomibis.com/coolclock/\n *\n */\n\n// Constructor for CoolClock objects\nwindow.CoolClock = function(options) {\n\treturn this.init(options);\n}\n\n// Config contains some defaults, and clock skins\nCoolClock.config = {\n\ttickDelay: 1000,\n\tlongTickDelay: 15000,\n\tdefaultRadius: 85,\n\trenderRadius: 100,\n\tdefaultSkin: \"chunkySwiss\",\n\t// Should be in skin probably...\n\t// (TODO: allow skinning of digital display)\n\tshowSecs: true,\n\tshowAmPm: true,\n\n\tskins:\t{\n\t\t// There are more skins in moreskins.js\n\t\t// Try making your own skin by copy/pasting one of these and tweaking it\n\t\tswissRail: {\n\t\t\touterBorder: { lineWidth: 2, radius:95, color: \"black\", alpha: 1 },\n\t\t\tsmallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: \"black\", alpha: 1 },\n\t\t\tlargeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: \"black\", alpha: 1 },\n\t\t\thourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: \"black\", alpha: 1 },\n\t\t\tminuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: \"black\", alpha: 1 },\n\t\t\tsecondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\t\tsecondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t\t},\n\t\tchunkySwiss: {\n\t\t\touterBorder: { lineWidth: 4, radius:97, color: \"black\", alpha: 1 },\n\t\t\tsmallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: \"black\", alpha: 1 },\n\t\t\tlargeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: \"black\", alpha: 1 },\n\t\t\thourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: \"black\", alpha: 1 },\n\t\t\tminuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: \"black\", alpha: 1 },\n\t\t\tsecondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\t\tsecondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t\t},\n\t\tchunkySwissOnBlack: {\n\t\t\touterBorder: { lineWidth: 4, radius:97, color: \"white\", alpha: 1 },\n\t\t\tsmallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: \"white\", alpha: 1 },\n\t\t\tlargeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: \"white\", alpha: 1 },\n\t\t\thourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: \"white\", alpha: 1 },\n\t\t\tminuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: \"white\", alpha: 1 },\n\t\t\tsecondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\t\tsecondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t\t}\n\n\t},\n\n\t// Test for IE so we can nurse excanvas in a couple of places\n\tisIE: !!document.all,\n\n\t// Will store (a reference to) each clock here, indexed by the id of the canvas element\n\tclockTracker: {},\n\n\t// For giving a unique id to coolclock canvases with no id\n\tnoIdCount: 0\n};\n\n// Define the CoolClock object's methods\nCoolClock.prototype = {\n\n\t// Initialise using the parameters parsed from the colon delimited class\n\tinit: function(options) {\n\t\t// Parse and store the options\n\t\tthis.canvasId       = options.canvasId;\n\t\tthis.skinId         = options.skinId || CoolClock.config.defaultSkin;\n\t\tthis.displayRadius  = options.displayRadius || CoolClock.config.defaultRadius;\n\t\tthis.showSecondHand = typeof options.showSecondHand == \"boolean\" ? options.showSecondHand : true;\n\t\tthis.gmtOffset      = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;\n\t\tthis.showDigital    = typeof options.showDigital == \"boolean\" ? options.showDigital : false;\n\t\tthis.logClock       = typeof options.logClock == \"boolean\" ? options.logClock : false;\n\t\tthis.logClockRev    = typeof options.logClock == \"boolean\" ? options.logClockRev : false;\n\n\t\tthis.tickDelay      = CoolClock.config[ this.showSecondHand ? \"tickDelay\" : \"longTickDelay\" ];\n\n\t\t// Get the canvas element\n\t\tthis.canvas = document.getElementById(this.canvasId);\n\n\t\t// Make the canvas the requested size. It's always square.\n\t\tthis.canvas.setAttribute(\"width\",this.displayRadius*2);\n\t\tthis.canvas.setAttribute(\"height\",this.displayRadius*2);\n\t\tthis.canvas.style.width = this.displayRadius*2 + \"px\";\n\t\tthis.canvas.style.height = this.displayRadius*2 + \"px\";\n\n\t\t// Explain me please...?\n\t\tthis.renderRadius = CoolClock.config.renderRadius;\n\t\tthis.scale = this.displayRadius / this.renderRadius;\n\n\t\t// Initialise canvas context\n\t\tthis.ctx = this.canvas.getContext(\"2d\");\n\t\tthis.ctx.scale(this.scale,this.scale);\n\n\t\t// Keep track of this object\n\t\tCoolClock.config.clockTracker[this.canvasId] = this;\n\n\t\t// Start the clock going\n\t\tthis.tick();\n\n\t\treturn this;\n\t},\n\n\t// Draw a circle at point x,y with params as defined in skin\n\tfullCircleAt: function(x,y,skin) {\n\t\tthis.ctx.save();\n\t\tthis.ctx.globalAlpha = skin.alpha;\n\t\tthis.ctx.lineWidth = skin.lineWidth;\n\n\t\tif (!CoolClock.config.isIE) {\n\t\t\tthis.ctx.beginPath();\n\t\t}\n\n\t\tif (CoolClock.config.isIE) {\n\t\t\t// excanvas doesn't scale line width so we will do it here\n\t\t\tthis.ctx.lineWidth = this.ctx.lineWidth * this.scale;\n\t\t}\n\n\t\tthis.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);\n\n\t\tif (CoolClock.config.isIE) {\n\t\t\t// excanvas doesn't close the circle so let's fill in the tiny gap\n\t\t\tthis.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);\n\t\t}\n\n\t\tif (skin.fillColor) {\n\t\t\tthis.ctx.fillStyle = skin.fillColor\n\t\t\tthis.ctx.fill();\n\t\t}\n\t\telse {\n\t\t\t// XXX why not stroke and fill\n\t\t\tthis.ctx.strokeStyle = skin.color;\n\t\t\tthis.ctx.stroke();\n\t\t}\n\t\tthis.ctx.restore();\n\t},\n\n\t// Draw some text centered vertically and horizontally\n\tdrawTextAt: function(theText,x,y) {\n\t\tthis.ctx.save();\n\t\tthis.ctx.font = '15px sans-serif';\n\t\tvar tSize = this.ctx.measureText(theText);\n\t\tif (!tSize.height) tSize.height = 15; // no height in firefox.. :(\n\t\tthis.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2);\n\t\tthis.ctx.restore();\n\t},\n\n\tlpad2: function(num) {\n\t\treturn (num < 10 ? '0' : '') + num;\n\t},\n\n\ttickAngle: function(second) {\n\t\t// Log algorithm by David Bradshaw\n\t\tvar tweak = 3; // If it's lower the one second mark looks wrong (?)\n\t\tif (this.logClock) {\n\t\t\treturn second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));\n\t\t}\n\t\telse if (this.logClockRev) {\n\t\t\t// Flip the seconds then flip the angle (trickiness)\n\t\t\tsecond = (60 - second) % 60;\n\t\t\treturn 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));\n\t\t}\n\t\telse {\n\t\t\treturn second/60.0;\n\t\t}\n\t},\n\n\ttimeText: function(hour,min,sec) {\n\t\tvar c = CoolClock.config;\n\t\treturn '' +\n\t\t\t(c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +\n\t\t\tthis.lpad2(min) +\n\t\t\t(c.showSecs ? ':' + this.lpad2(sec) : '') +\n\t\t\t(c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '')\n\t\t;\n\t},\n\n\t// Draw a radial line by rotating then drawing a straight line\n\t// Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)\n\tradialLineAtAngle: function(angleFraction,skin) {\n\t\tthis.ctx.save();\n\t\tthis.ctx.translate(this.renderRadius,this.renderRadius);\n\t\tthis.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));\n\t\tthis.ctx.globalAlpha = skin.alpha;\n\t\tthis.ctx.strokeStyle = skin.color;\n\t\tthis.ctx.lineWidth = skin.lineWidth;\n\n\t\tif (CoolClock.config.isIE)\n\t\t\t// excanvas doesn't scale line width so we will do it here\n\t\t\tthis.ctx.lineWidth = this.ctx.lineWidth * this.scale;\n\n\t\tif (skin.radius) {\n\t\t\tthis.fullCircleAt(skin.startAt,0,skin)\n\t\t}\n\t\telse {\n\t\t\tthis.ctx.beginPath();\n\t\t\tthis.ctx.moveTo(skin.startAt,0)\n\t\t\tthis.ctx.lineTo(skin.endAt,0);\n\t\t\tthis.ctx.stroke();\n\t\t}\n\t\tthis.ctx.restore();\n\t},\n\n\trender: function(hour,min,sec) {\n\t\t// Get the skin\n\t\tvar skin = CoolClock.config.skins[this.skinId];\n\t\tif (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];\n\n\t\t// Clear\n\t\tthis.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);\n\n\t\t// Draw the outer edge of the clock\n\t\tif (skin.outerBorder)\n\t\t\tthis.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);\n\n\t\t// Draw the tick marks. Every 5th one is a big one\n\t\tfor (var i=0;i<60;i++) {\n\t\t\t(i%5)  && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);\n\t\t\t!(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);\n\t\t}\n\n\t\t// Write the time\n\t\tif (this.showDigital) {\n\t\t\tthis.drawTextAt(\n\t\t\t\tthis.timeText(hour,min,sec),\n\t\t\t\tthis.renderRadius,\n\t\t\t\tthis.renderRadius+this.renderRadius/2\n\t\t\t);\n\t\t}\n\n\t\t// Draw the hands\n\t\tif (skin.hourHand)\n\t\t\tthis.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand);\n\n\t\tif (skin.minuteHand)\n\t\t\tthis.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand);\n\n\t\tif (this.showSecondHand && skin.secondHand)\n\t\t\tthis.radialLineAtAngle(this.tickAngle(sec),skin.secondHand);\n\n\t\t// Second hand decoration doesn't render right in IE so lets turn it off\n\t\tif (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration)\n\t\t\tthis.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration);\n\t},\n\n\t// Check the time and display the clock\n\trefreshDisplay: function() {\n\t\tvar now = new Date();\n\t\tif (this.gmtOffset != null) {\n\t\t\t// Use GMT + gmtOffset\n\t\t\tvar offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));\n\t\t\tthis.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds());\n\t\t}\n\t\telse {\n\t\t\t// Use local time\n\t\t\tthis.render(now.getHours(),now.getMinutes(),now.getSeconds());\n\t\t}\n\t},\n\n\t// Set timeout to trigger a tick in the future\n\tnextTick: function() {\n\t\tsetTimeout(\"CoolClock.config.clockTracker['\"+this.canvasId+\"'].tick()\",this.tickDelay);\n\t},\n\n\t// Check the canvas element hasn't been removed\n\tstillHere: function() {\n\t\treturn document.getElementById(this.canvasId) != null;\n\t},\n\n\t// Main tick handler. Refresh the clock then setup the next tick\n\ttick: function() {\n\t\tif (this.stillHere()) {\n\t\t\tthis.refreshDisplay()\n\t\t\tthis.nextTick();\n\t\t}\n\t}\n};\n\n// Find all canvas elements that have the CoolClock class and turns them into clocks\nCoolClock.findAndCreateClocks = function() {\n\t// (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)\n\tvar canvases = document.getElementsByTagName(\"canvas\");\n\tfor (var i=0;i<canvases.length;i++) {\n\t\t// Pull out the fields from the class. Example \"CoolClock:chunkySwissOnBlack:1000\"\n\t\tvar fields = canvases[i].className.split(\" \")[0].split(\":\");\n\t\tif (fields[0] == \"CoolClock\") {\n\t\t\tif (!canvases[i].id) {\n\t\t\t\t// If there's no id on this canvas element then give it one\n\t\t\t\tcanvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;\n\t\t\t}\n\t\t\t// Create a clock object for this element\n\t\t\tnew CoolClock({\n\t\t\t\tcanvasId:       canvases[i].id,\n\t\t\t\tskinId:         fields[1],\n\t\t\t\tdisplayRadius:  fields[2],\n\t\t\t\tshowSecondHand: fields[3]!='noSeconds',\n\t\t\t\tgmtOffset:      fields[4],\n\t\t\t\tshowDigital:    fields[5]=='showDigital',\n\t\t\t\tlogClock:       fields[6]=='logClock',\n\t\t\t\tlogClockRev:    fields[6]=='logClockRev'\n\t\t\t});\n\t\t}\n\t}\n};\n\n// If you don't have jQuery then you need a body onload like this: <body onload=\"CoolClock.findAndCreateClocks()\">\n// If you do have jQuery and it's loaded already then we can do it right now\nif (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);\n"
  },
  {
    "path": "input-scripts/coolclock/excanvas.js",
    "content": "// Copyright 2006 Google Inc.\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// Known Issues:\n//\n// * Patterns are not implemented.\n// * Radial gradient are not implemented. The VML version of these look very\n//   different from the canvas one.\n// * Clipping paths are not implemented.\n// * Coordsize. The width and height attribute have higher priority than the\n//   width and height style values which isn't correct.\n// * Painting mode isn't implemented.\n// * Canvas width/height should is using content-box by default. IE in\n//   Quirks mode will draw the canvas using border-box. Either change your\n//   doctype to HTML5\n//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)\n//   or use Box Sizing Behavior from WebFX\n//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)\n// * Optimize. There is always room for speed improvements.\n\n// only add this code if we do not already have a canvas implementation\nif (!window.CanvasRenderingContext2D) {\n\n(function () {\n\n  // alias some functions to make (compiled) code shorter\n  var m = Math;\n  var mr = m.round;\n  var ms = m.sin;\n  var mc = m.cos;\n\n  // this is used for sub pixel precision\n  var Z = 10;\n  var Z2 = Z / 2;\n\n  var G_vmlCanvasManager_ = {\n    init: function (opt_doc) {\n      var doc = opt_doc || document;\n      if (/MSIE/.test(navigator.userAgent) && !window.opera) {\n        var self = this;\n        doc.attachEvent(\"onreadystatechange\", function () {\n          self.init_(doc);\n        });\n      }\n    },\n\n    init_: function (doc) {\n      if (doc.readyState == \"complete\") {\n        // create xmlns\n        if (!doc.namespaces[\"g_vml_\"]) {\n          doc.namespaces.add(\"g_vml_\", \"urn:schemas-microsoft-com:vml\");\n        }\n\n        // setup default css\n        var ss = doc.createStyleSheet();\n        ss.cssText = \"canvas{display:inline-block;overflow:hidden;\" +\n            // default size is 300x150 in Gecko and Opera\n            \"text-align:left;width:300px;height:150px}\" +\n            \"g_vml_\\\\:*{behavior:url(#default#VML)}\";\n\n        // find all canvas elements\n        var els = doc.getElementsByTagName(\"canvas\");\n        for (var i = 0; i < els.length; i++) {\n          if (!els[i].getContext) {\n            this.initElement(els[i]);\n          }\n        }\n      }\n    },\n\n    fixElement_: function (el) {\n      // in IE before version 5.5 we would need to add HTML: to the tag name\n      // but we do not care about IE before version 6\n      var outerHTML = el.outerHTML;\n\n      var newEl = el.ownerDocument.createElement(outerHTML);\n      // if the tag is still open IE has created the children as siblings and\n      // it has also created a tag with the name \"/FOO\"\n      if (outerHTML.slice(-2) != \"/>\") {\n        var tagName = \"/\" + el.tagName;\n        var ns;\n        // remove content\n        while ((ns = el.nextSibling) && ns.tagName != tagName) {\n          ns.removeNode();\n        }\n        // remove the incorrect closing tag\n        if (ns) {\n          ns.removeNode();\n        }\n      }\n      el.parentNode.replaceChild(newEl, el);\n      return newEl;\n    },\n\n    /**\n     * Public initializes a canvas element so that it can be used as canvas\n     * element from now on. This is called automatically before the page is\n     * loaded but if you are creating elements using createElement you need to\n     * make sure this is called on the element.\n     * @param {HTMLElement} el The canvas element to initialize.\n     * @return {HTMLElement} the element that was created.\n     */\n    initElement: function (el) {\n      el = this.fixElement_(el);\n      el.getContext = function () {\n        if (this.context_) {\n          return this.context_;\n        }\n        return this.context_ = new CanvasRenderingContext2D_(this);\n      };\n\n      // do not use inline function because that will leak memory\n      el.attachEvent('onpropertychange', onPropertyChange);\n      el.attachEvent('onresize', onResize);\n\n      var attrs = el.attributes;\n      if (attrs.width && attrs.width.specified) {\n        // TODO: use runtimeStyle and coordsize\n        // el.getContext().setWidth_(attrs.width.nodeValue);\n        el.style.width = attrs.width.nodeValue + \"px\";\n      } else {\n        el.width = el.clientWidth;\n      }\n      if (attrs.height && attrs.height.specified) {\n        // TODO: use runtimeStyle and coordsize\n        // el.getContext().setHeight_(attrs.height.nodeValue);\n        el.style.height = attrs.height.nodeValue + \"px\";\n      } else {\n        el.height = el.clientHeight;\n      }\n      //el.getContext().setCoordsize_()\n      return el;\n    }\n  };\n\n  function onPropertyChange(e) {\n    var el = e.srcElement;\n\n    switch (e.propertyName) {\n      case 'width':\n        el.style.width = el.attributes.width.nodeValue + \"px\";\n        el.getContext().clearRect();\n        break;\n      case 'height':\n        el.style.height = el.attributes.height.nodeValue + \"px\";\n        el.getContext().clearRect();\n        break;\n    }\n  }\n\n  function onResize(e) {\n    var el = e.srcElement;\n    if (el.firstChild) {\n      el.firstChild.style.width =  el.clientWidth + 'px';\n      el.firstChild.style.height = el.clientHeight + 'px';\n    }\n  }\n\n  G_vmlCanvasManager_.init();\n\n  // precompute \"00\" to \"FF\"\n  var dec2hex = [];\n  for (var i = 0; i < 16; i++) {\n    for (var j = 0; j < 16; j++) {\n      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);\n    }\n  }\n\n  function createMatrixIdentity() {\n    return [\n      [1, 0, 0],\n      [0, 1, 0],\n      [0, 0, 1]\n    ];\n  }\n\n  function matrixMultiply(m1, m2) {\n    var result = createMatrixIdentity();\n\n    for (var x = 0; x < 3; x++) {\n      for (var y = 0; y < 3; y++) {\n        var sum = 0;\n\n        for (var z = 0; z < 3; z++) {\n          sum += m1[x][z] * m2[z][y];\n        }\n\n        result[x][y] = sum;\n      }\n    }\n    return result;\n  }\n\n  function copyState(o1, o2) {\n    o2.fillStyle     = o1.fillStyle;\n    o2.lineCap       = o1.lineCap;\n    o2.lineJoin      = o1.lineJoin;\n    o2.lineWidth     = o1.lineWidth;\n    o2.miterLimit    = o1.miterLimit;\n    o2.shadowBlur    = o1.shadowBlur;\n    o2.shadowColor   = o1.shadowColor;\n    o2.shadowOffsetX = o1.shadowOffsetX;\n    o2.shadowOffsetY = o1.shadowOffsetY;\n    o2.strokeStyle   = o1.strokeStyle;\n    o2.arcScaleX_    = o1.arcScaleX_;\n    o2.arcScaleY_    = o1.arcScaleY_;\n  }\n\n  function processStyle(styleString) {\n    var str, alpha = 1;\n\n    styleString = String(styleString);\n    if (styleString.substring(0, 3) == \"rgb\") {\n      var start = styleString.indexOf(\"(\", 3);\n      var end = styleString.indexOf(\")\", start + 1);\n      var guts = styleString.substring(start + 1, end).split(\",\");\n\n      str = \"#\";\n      for (var i = 0; i < 3; i++) {\n        str += dec2hex[Number(guts[i])];\n      }\n\n      if ((guts.length == 4) && (styleString.substr(3, 1) == \"a\")) {\n        alpha = guts[3];\n      }\n    } else {\n      str = styleString;\n    }\n\n    return [str, alpha];\n  }\n\n  function processLineCap(lineCap) {\n    switch (lineCap) {\n      case \"butt\":\n        return \"flat\";\n      case \"round\":\n        return \"round\";\n      case \"square\":\n      default:\n        return \"square\";\n    }\n  }\n\n  /**\n   * This class implements CanvasRenderingContext2D interface as described by\n   * the WHATWG.\n   * @param {HTMLElement} surfaceElement The element that the 2D context should\n   * be associated with\n   */\n   function CanvasRenderingContext2D_(surfaceElement) {\n    this.m_ = createMatrixIdentity();\n\n    this.mStack_ = [];\n    this.aStack_ = [];\n    this.currentPath_ = [];\n\n    // Canvas context properties\n    this.strokeStyle = \"#000\";\n    this.fillStyle = \"#000\";\n\n    this.lineWidth = 1;\n    this.lineJoin = \"miter\";\n    this.lineCap = \"butt\";\n    this.miterLimit = Z * 1;\n    this.globalAlpha = 1;\n    this.canvas = surfaceElement;\n\n    var el = surfaceElement.ownerDocument.createElement('div');\n    el.style.width =  surfaceElement.clientWidth + 'px';\n    el.style.height = surfaceElement.clientHeight + 'px';\n    el.style.overflow = 'hidden';\n    el.style.position = 'absolute';\n    surfaceElement.appendChild(el);\n\n    this.element_ = el;\n    this.arcScaleX_ = 1;\n    this.arcScaleY_ = 1;\n  };\n\n  var contextPrototype = CanvasRenderingContext2D_.prototype;\n  contextPrototype.clearRect = function() {\n    this.element_.innerHTML = \"\";\n    this.currentPath_ = [];\n  };\n\n  contextPrototype.beginPath = function() {\n    // TODO: Branch current matrix so that save/restore has no effect\n    //       as per safari docs.\n\n    this.currentPath_ = [];\n  };\n\n  contextPrototype.moveTo = function(aX, aY) {\n    this.currentPath_.push({type: \"moveTo\", x: aX, y: aY});\n    this.currentX_ = aX;\n    this.currentY_ = aY;\n  };\n\n  contextPrototype.lineTo = function(aX, aY) {\n    this.currentPath_.push({type: \"lineTo\", x: aX, y: aY});\n    this.currentX_ = aX;\n    this.currentY_ = aY;\n  };\n\n  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,\n                                            aCP2x, aCP2y,\n                                            aX, aY) {\n    this.currentPath_.push({type: \"bezierCurveTo\",\n                           cp1x: aCP1x,\n                           cp1y: aCP1y,\n                           cp2x: aCP2x,\n                           cp2y: aCP2y,\n                           x: aX,\n                           y: aY});\n    this.currentX_ = aX;\n    this.currentY_ = aY;\n  };\n\n  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {\n    // the following is lifted almost directly from\n    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes\n    var cp1x = this.currentX_ + 2.0 / 3.0 * (aCPx - this.currentX_);\n    var cp1y = this.currentY_ + 2.0 / 3.0 * (aCPy - this.currentY_);\n    var cp2x = cp1x + (aX - this.currentX_) / 3.0;\n    var cp2y = cp1y + (aY - this.currentY_) / 3.0;\n    this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, aX, aY);\n  };\n\n  contextPrototype.arc = function(aX, aY, aRadius,\n                                  aStartAngle, aEndAngle, aClockwise) {\n    aRadius *= Z;\n    var arcType = aClockwise ? \"at\" : \"wa\";\n\n    var xStart = aX + (mc(aStartAngle) * aRadius) - Z2;\n    var yStart = aY + (ms(aStartAngle) * aRadius) - Z2;\n\n    var xEnd = aX + (mc(aEndAngle) * aRadius) - Z2;\n    var yEnd = aY + (ms(aEndAngle) * aRadius) - Z2;\n\n    // IE won't render arches drawn counter clockwise if xStart == xEnd.\n    if (xStart == xEnd && !aClockwise) {\n      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something\n                       // that can be represented in binary\n    }\n\n    this.currentPath_.push({type: arcType,\n                           x: aX,\n                           y: aY,\n                           radius: aRadius,\n                           xStart: xStart,\n                           yStart: yStart,\n                           xEnd: xEnd,\n                           yEnd: yEnd});\n\n  };\n\n  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n  };\n\n  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {\n    // Will destroy any existing path (same as FF behaviour)\n    this.beginPath();\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n    this.stroke();\n  };\n\n  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {\n    // Will destroy any existing path (same as FF behaviour)\n    this.beginPath();\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n    this.fill();\n  };\n\n  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {\n    var gradient = new CanvasGradient_(\"gradient\");\n    return gradient;\n  };\n\n  contextPrototype.createRadialGradient = function(aX0, aY0,\n                                                   aR0, aX1,\n                                                   aY1, aR1) {\n    var gradient = new CanvasGradient_(\"gradientradial\");\n    gradient.radius1_ = aR0;\n    gradient.radius2_ = aR1;\n    gradient.focus_.x = aX0;\n    gradient.focus_.y = aY0;\n    return gradient;\n  };\n\n  contextPrototype.drawImage = function (image, var_args) {\n    var dx, dy, dw, dh, sx, sy, sw, sh;\n\n    // to find the original width we overide the width and height\n    var oldRuntimeWidth = image.runtimeStyle.width;\n    var oldRuntimeHeight = image.runtimeStyle.height;\n    image.runtimeStyle.width = 'auto';\n    image.runtimeStyle.height = 'auto';\n\n    // get the original size\n    var w = image.width;\n    var h = image.height;\n\n    // and remove overides\n    image.runtimeStyle.width = oldRuntimeWidth;\n    image.runtimeStyle.height = oldRuntimeHeight;\n\n    if (arguments.length == 3) {\n      dx = arguments[1];\n      dy = arguments[2];\n      sx = sy = 0;\n      sw = dw = w;\n      sh = dh = h;\n    } else if (arguments.length == 5) {\n      dx = arguments[1];\n      dy = arguments[2];\n      dw = arguments[3];\n      dh = arguments[4];\n      sx = sy = 0;\n      sw = w;\n      sh = h;\n    } else if (arguments.length == 9) {\n      sx = arguments[1];\n      sy = arguments[2];\n      sw = arguments[3];\n      sh = arguments[4];\n      dx = arguments[5];\n      dy = arguments[6];\n      dw = arguments[7];\n      dh = arguments[8];\n    } else {\n      throw \"Invalid number of arguments\";\n    }\n\n    var d = this.getCoords_(dx, dy);\n\n    var w2 = sw / 2;\n    var h2 = sh / 2;\n\n    var vmlStr = [];\n\n    var W = 10;\n    var H = 10;\n\n    // For some reason that I've now forgotten, using divs didn't work\n    vmlStr.push(' <g_vml_:group',\n                ' coordsize=\"', Z * W, ',', Z * H, '\"',\n                ' coordorigin=\"0,0\"' ,\n                ' style=\"width:', W, ';height:', H, ';position:absolute;');\n\n    // If filters are necessary (rotation exists), create them\n    // filters are bog-slow, so only create them if abbsolutely necessary\n    // The following check doesn't account for skews (which don't exist\n    // in the canvas spec (yet) anyway.\n\n    if (this.m_[0][0] != 1 || this.m_[0][1]) {\n      var filter = [];\n\n      // Note the 12/21 reversal\n      filter.push(\"M11='\", this.m_[0][0], \"',\",\n                  \"M12='\", this.m_[1][0], \"',\",\n                  \"M21='\", this.m_[0][1], \"',\",\n                  \"M22='\", this.m_[1][1], \"',\",\n                  \"Dx='\", mr(d.x / Z), \"',\",\n                  \"Dy='\", mr(d.y / Z), \"'\");\n\n      // Bounding box calculation (need to minimize displayed area so that\n      // filters don't waste time on unused pixels.\n      var max = d;\n      var c2 = this.getCoords_(dx + dw, dy);\n      var c3 = this.getCoords_(dx, dy + dh);\n      var c4 = this.getCoords_(dx + dw, dy + dh);\n\n      max.x = Math.max(max.x, c2.x, c3.x, c4.x);\n      max.y = Math.max(max.y, c2.y, c3.y, c4.y);\n\n      vmlStr.push(\"padding:0 \", mr(max.x / Z), \"px \", mr(max.y / Z),\n                  \"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(\",\n                  filter.join(\"\"), \", sizingmethod='clip');\")\n    } else {\n      vmlStr.push(\"top:\", mr(d.y / Z), \"px;left:\", mr(d.x / Z), \"px;\")\n    }\n\n    vmlStr.push(' \">' ,\n                '<g_vml_:image src=\"', image.src, '\"',\n                ' style=\"width:', Z * dw, ';',\n                ' height:', Z * dh, ';\"',\n                ' cropleft=\"', sx / w, '\"',\n                ' croptop=\"', sy / h, '\"',\n                ' cropright=\"', (w - sx - sw) / w, '\"',\n                ' cropbottom=\"', (h - sy - sh) / h, '\"',\n                ' />',\n                '</g_vml_:group>');\n\n    this.element_.insertAdjacentHTML(\"BeforeEnd\",\n                                    vmlStr.join(\"\"));\n  };\n\n  contextPrototype.stroke = function(aFill) {\n    var lineStr = [];\n    var lineOpen = false;\n    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);\n    var color = a[0];\n    var opacity = a[1] * this.globalAlpha;\n\n    var W = 10;\n    var H = 10;\n\n    lineStr.push('<g_vml_:shape',\n                 ' fillcolor=\"', color, '\"',\n                 ' filled=\"', Boolean(aFill), '\"',\n                 ' style=\"position:absolute;width:', W, ';height:', H, ';\"',\n                 ' coordorigin=\"0 0\" coordsize=\"', Z * W, ' ', Z * H, '\"',\n                 ' stroked=\"', !aFill, '\"',\n                 ' strokeweight=\"', this.lineWidth, '\"',\n                 ' strokecolor=\"', color, '\"',\n                 ' path=\"');\n\n    var newSeq = false;\n    var min = {x: null, y: null};\n    var max = {x: null, y: null};\n\n    for (var i = 0; i < this.currentPath_.length; i++) {\n      var p = this.currentPath_[i];\n\n      if (p.type == \"moveTo\") {\n        lineStr.push(\" m \");\n        var c = this.getCoords_(p.x, p.y);\n        lineStr.push(mr(c.x), \",\", mr(c.y));\n      } else if (p.type == \"lineTo\") {\n        lineStr.push(\" l \");\n        var c = this.getCoords_(p.x, p.y);\n        lineStr.push(mr(c.x), \",\", mr(c.y));\n      } else if (p.type == \"close\") {\n        lineStr.push(\" x \");\n      } else if (p.type == \"bezierCurveTo\") {\n        lineStr.push(\" c \");\n        var c = this.getCoords_(p.x, p.y);\n        var c1 = this.getCoords_(p.cp1x, p.cp1y);\n        var c2 = this.getCoords_(p.cp2x, p.cp2y);\n        lineStr.push(mr(c1.x), \",\", mr(c1.y), \",\",\n                     mr(c2.x), \",\", mr(c2.y), \",\",\n                     mr(c.x), \",\", mr(c.y));\n      } else if (p.type == \"at\" || p.type == \"wa\") {\n        lineStr.push(\" \", p.type, \" \");\n        var c  = this.getCoords_(p.x, p.y);\n        var cStart = this.getCoords_(p.xStart, p.yStart);\n        var cEnd = this.getCoords_(p.xEnd, p.yEnd);\n\n        lineStr.push(mr(c.x - this.arcScaleX_ * p.radius), \",\",\n                     mr(c.y - this.arcScaleY_ * p.radius), \" \",\n                     mr(c.x + this.arcScaleX_ * p.radius), \",\",\n                     mr(c.y + this.arcScaleY_ * p.radius), \" \",\n                     mr(cStart.x), \",\", mr(cStart.y), \" \",\n                     mr(cEnd.x), \",\", mr(cEnd.y));\n      }\n\n\n      // TODO: Following is broken for curves due to\n      //       move to proper paths.\n\n      // Figure out dimensions so we can do gradient fills\n      // properly\n      if(c) {\n        if (min.x == null || c.x < min.x) {\n          min.x = c.x;\n        }\n        if (max.x == null || c.x > max.x) {\n          max.x = c.x;\n        }\n        if (min.y == null || c.y < min.y) {\n          min.y = c.y;\n        }\n        if (max.y == null || c.y > max.y) {\n          max.y = c.y;\n        }\n      }\n    }\n    lineStr.push(' \">');\n\n    if (typeof this.fillStyle == \"object\") {\n      var focus = {x: \"50%\", y: \"50%\"};\n      var width = (max.x - min.x);\n      var height = (max.y - min.y);\n      var dimension = (width > height) ? width : height;\n\n      focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + \"%\";\n      focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + \"%\";\n\n      var colors = [];\n\n      // inside radius (%)\n      if (this.fillStyle.type_ == \"gradientradial\") {\n        var inside = (this.fillStyle.radius1_ / dimension * 100);\n\n        // percentage that outside radius exceeds inside radius\n        var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside;\n      } else {\n        var inside = 0;\n        var expansion = 100;\n      }\n\n      var insidecolor = {offset: null, color: null};\n      var outsidecolor = {offset: null, color: null};\n\n      // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie\n      // won't interpret it correctly\n      this.fillStyle.colors_.sort(function (cs1, cs2) {\n        return cs1.offset - cs2.offset;\n      });\n\n      for (var i = 0; i < this.fillStyle.colors_.length; i++) {\n        var fs = this.fillStyle.colors_[i];\n\n        colors.push( (fs.offset * expansion) + inside, \"% \", fs.color, \",\");\n\n        if (fs.offset > insidecolor.offset || insidecolor.offset == null) {\n          insidecolor.offset = fs.offset;\n          insidecolor.color = fs.color;\n        }\n\n        if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {\n          outsidecolor.offset = fs.offset;\n          outsidecolor.color = fs.color;\n        }\n      }\n      colors.pop();\n\n      lineStr.push('<g_vml_:fill',\n                   ' color=\"', outsidecolor.color, '\"',\n                   ' color2=\"', insidecolor.color, '\"',\n                   ' type=\"', this.fillStyle.type_, '\"',\n                   ' focusposition=\"', focus.x, ', ', focus.y, '\"',\n                   ' colors=\"', colors.join(\"\"), '\"',\n                   ' opacity=\"', opacity, '\" />');\n    } else if (aFill) {\n      lineStr.push('<g_vml_:fill color=\"', color, '\" opacity=\"', opacity, '\" />');\n    } else {\n      lineStr.push(\n        '<g_vml_:stroke',\n        ' opacity=\"', opacity,'\"',\n        ' joinstyle=\"', this.lineJoin, '\"',\n        ' miterlimit=\"', this.miterLimit, '\"',\n        ' endcap=\"', processLineCap(this.lineCap) ,'\"',\n        ' weight=\"', this.lineWidth, 'px\"',\n        ' color=\"', color,'\" />'\n      );\n    }\n\n    lineStr.push(\"</g_vml_:shape>\");\n\n    this.element_.insertAdjacentHTML(\"beforeEnd\", lineStr.join(\"\"));\n\n    this.currentPath_ = [];\n  };\n\n  contextPrototype.fill = function() {\n    this.stroke(true);\n  }\n\n  contextPrototype.closePath = function() {\n    this.currentPath_.push({type: \"close\"});\n  };\n\n  /**\n   * @private\n   */\n  contextPrototype.getCoords_ = function(aX, aY) {\n    return {\n      x: Z * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - Z2,\n      y: Z * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - Z2\n    }\n  };\n\n  contextPrototype.save = function() {\n    var o = {};\n    copyState(this, o);\n    this.aStack_.push(o);\n    this.mStack_.push(this.m_);\n    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);\n  };\n\n  contextPrototype.restore = function() {\n    copyState(this.aStack_.pop(), this);\n    this.m_ = this.mStack_.pop();\n  };\n\n  contextPrototype.translate = function(aX, aY) {\n    var m1 = [\n      [1,  0,  0],\n      [0,  1,  0],\n      [aX, aY, 1]\n    ];\n\n    this.m_ = matrixMultiply(m1, this.m_);\n  };\n\n  contextPrototype.rotate = function(aRot) {\n    var c = mc(aRot);\n    var s = ms(aRot);\n\n    var m1 = [\n      [c,  s, 0],\n      [-s, c, 0],\n      [0,  0, 1]\n    ];\n\n    this.m_ = matrixMultiply(m1, this.m_);\n  };\n\n  contextPrototype.scale = function(aX, aY) {\n    this.arcScaleX_ *= aX;\n    this.arcScaleY_ *= aY;\n    var m1 = [\n      [aX, 0,  0],\n      [0,  aY, 0],\n      [0,  0,  1]\n    ];\n\n    this.m_ = matrixMultiply(m1, this.m_);\n  };\n\n  /******** STUBS ********/\n  contextPrototype.clip = function() {\n    // TODO: Implement\n  };\n\n  contextPrototype.arcTo = function() {\n    // TODO: Implement\n  };\n\n  contextPrototype.createPattern = function() {\n    return new CanvasPattern_;\n  };\n\n  // Gradient / Pattern Stubs\n  function CanvasGradient_(aType) {\n    this.type_ = aType;\n    this.radius1_ = 0;\n    this.radius2_ = 0;\n    this.colors_ = [];\n    this.focus_ = {x: 0, y: 0};\n  }\n\n  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {\n    aColor = processStyle(aColor);\n    this.colors_.push({offset: 1-aOffset, color: aColor});\n  };\n\n  function CanvasPattern_() {}\n\n  // set up externs\n  G_vmlCanvasManager = G_vmlCanvasManager_;\n  CanvasRenderingContext2D = CanvasRenderingContext2D_;\n  CanvasGradient = CanvasGradient_;\n  CanvasPattern = CanvasPattern_;\n\n})();\n\n} // if\n"
  },
  {
    "path": "input-scripts/coolclock/moreskins.js",
    "content": "CoolClock.config.skins = {\n\n\tswissRail: {\n\t\touterBorder:      { lineWidth: 2, radius: 95, color: \"black\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 2, startAt: 88, endAt: 92, color: \"black\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 4, startAt: 79, endAt: 92, color: \"black\", alpha: 1 },\n\t\thourHand:         { lineWidth: 8, startAt: -15, endAt: 50, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 7, startAt: -15, endAt: 75, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t},\n\n\tchunkySwiss: {\n\t\touterBorder:      { lineWidth: 4, radius: 97, color: \"black\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 4, startAt: 89, endAt: 93, color: \"black\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 8, startAt: 80, endAt: 93, color: \"black\", alpha: 1 },\n\t\thourHand:         { lineWidth: 12, startAt: -15, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 10, startAt: -15, endAt: 85, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 4, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t},\n\n\tchunkySwissOnBlack: {\n\t\touterBorder:      { lineWidth: 4, radius: 97, color: \"white\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 4, startAt: 89, endAt: 93, color: \"white\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 8, startAt: 80, endAt: 93, color: \"white\", alpha: 1 },\n\t\thourHand:         { lineWidth: 12, startAt: -15, endAt: 60, color: \"white\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 10, startAt: -15, endAt: 85, color: \"white\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 4, startAt: -20, endAt: 85, color: \"red\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: \"red\", color: \"red\", alpha: 1 }\n\t},\n\n\tfancy: {\n\t\touterBorder:      { lineWidth: 5, radius: 95, color: \"green\", alpha: 0.7 },\n\t\tsmallIndicator:   { lineWidth: 1, startAt: 80, endAt: 93, color: \"black\", alpha: 0.4 },\n\t\tlargeIndicator:   { lineWidth: 1, startAt: 30, endAt: 93, color: \"black\", alpha: 0.5 },\n\t\thourHand:         { lineWidth: 8, startAt: -15, endAt: 50, color: \"blue\", alpha: 0.7 },\n\t\tminuteHand:       { lineWidth: 7, startAt: -15, endAt: 92, color: \"red\", alpha: 0.7 },\n\t\tsecondHand:       { lineWidth: 10, startAt: 80, endAt: 85, color: \"blue\", alpha: 0.3 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 30, radius: 50, fillColor: \"blue\", color: \"red\", alpha: 0.15 }\n\t},\n\n\tmachine: {\n\t\touterBorder:      { lineWidth: 60, radius: 55, color: \"#dd6655\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 4, startAt: 80, endAt: 95, color: \"white\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 14, startAt: 77, endAt: 92, color: \"#dd6655\", alpha: 1 },\n\t\thourHand:         { lineWidth: 18, startAt: -15, endAt: 40, color: \"white\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 14, startAt: 24, endAt: 100, color: \"#771100\", alpha: 0.5 },\n\t\tsecondHand:       { lineWidth: 3, startAt: 22, endAt: 83, color: \"green\", alpha: 0 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 52, radius: 26, fillColor: \"#ffcccc\", color: \"red\", alpha: 0.5 }\n\t},\n\n\tsimonbaird_com: {\n\t\thourHand:         { lineWidth: 80, startAt: -15, endAt: 35,  color: 'magenta', alpha: 0.5 },\n\t\tminuteHand:       { lineWidth: 80, startAt: -15, endAt: 65,  color: 'cyan', alpha: 0.5 },\n\t\tsecondDecoration: { lineWidth: 1,  startAt: 40,  radius: 40, color: \"#fff\", fillColor: 'yellow', alpha: 0.5 }\n\t},\n\n\t// by bonstio, http://bonstio.net\n\tclassic/*was gIG*/: {\n\t\touterBorder:      { lineWidth: 185, radius: 1, color: \"#E5ECF9\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 2, startAt: 89, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 4, startAt: 83, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\thourHand:         { lineWidth: 5, startAt: 0, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 4, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: -20, endAt: 85, color: \"red\", alpha: .85 },\n\t\tsecondDecoration: { lineWidth: 3, startAt: 0, radius: 2, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tmodern/*was gIG2*/: {\n\t\touterBorder:      { lineWidth: 185, radius: 1, color: \"#E5ECF9\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 5, startAt: 88, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 5, startAt: 88, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\thourHand:         { lineWidth: 8, startAt: 0, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 8, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 5, startAt: 80, endAt: 85, color: \"red\", alpha: .85 },\n\t\tsecondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tsimple/*was gIG3*/: {\n\t\touterBorder:      { lineWidth: 185, radius: 1, color: \"#E5ECF9\", alpha: 1 },\n\t\tsmallIndicator:   { lineWidth: 10, startAt: 90, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 10, startAt: 90, endAt: 94, color: \"#3366CC\", alpha: 1 },\n\t\thourHand:         { lineWidth: 8, startAt: 0, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 8, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 5, startAt: 80, endAt: 85, color: \"red\", alpha: .85 },\n\t\tsecondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\t// by securephp\n\tsecurephp: {\n\t\touterBorder:      { lineWidth: 100, radius: 0.45, color: \"#669900\", alpha: 0.3 },\n\t\tsmallIndicator:   { lineWidth: 2, startAt: 80, endAt: 90 , color: \"green\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 8.5, startAt: 20, endAt: 40 , color: \"green\", alpha: 0.4 },\n\t\thourHand:         { lineWidth: 3, startAt: 0, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 2, startAt: 0, endAt: 75, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: -10, endAt: 80, color: \"blue\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: \"blue\", color: \"red\", alpha: 1 }\n\t},\n\n\tTes2: {\n\t\touterBorder:      { lineWidth: 4, radius: 95, color: \"black\", alpha: 0.5 },\n\t\tsmallIndicator:   { lineWidth: 1, startAt: 10, endAt: 50 , color: \"#66CCFF\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 8.5, startAt: 60, endAt: 70, color: \"#6699FF\", alpha: 1 },\n\t\thourHand:         { lineWidth: 5, startAt: -15, endAt: 60, color: \"black\", alpha: 0.7 },\n\t\tminuteHand:       { lineWidth: 3, startAt: -25, endAt: 75, color: \"black\", alpha: 0.7 },\n\t\tsecondHand:       { lineWidth: 1.5, startAt: -20, endAt: 88, color: \"red\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 20, radius: 4, fillColor: \"blue\", color: \"red\", alpha: 1 }\n\t},\n\n\n\tLev: {\n\t\touterBorder:      { lineWidth: 10, radius: 95, color: \"#CCFF33\", alpha: 0.65 },\n\t\tsmallIndicator:   { lineWidth: 5, startAt: 84, endAt: 90, color: \"#996600\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 40, startAt: 25, endAt: 95, color: \"#336600\", alpha: 0.55 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 0.9 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 0.85 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: \"black\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tSand: {\n\t\touterBorder:      { lineWidth: 1, radius: 70, color: \"black\", alpha: 0.5 },\n\t\tsmallIndicator:   { lineWidth: 3, startAt: 50, endAt: 70, color: \"#0066FF\", alpha: 0.5 },\n\t\tlargeIndicator:   { lineWidth: 200, startAt: 80, endAt: 95, color: \"#996600\", alpha: 0.75 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 0.9 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 0.85 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: \"black\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tSun: {\n\t\touterBorder:      { lineWidth: 100, radius: 140, color: \"#99FFFF\", alpha: 0.2 },\n\t\tsmallIndicator:   { lineWidth: 300, startAt: 50, endAt: 70, color: \"black\", alpha: 0.1 },\n\t\tlargeIndicator:   { lineWidth: 5, startAt: 80, endAt: 95, color: \"black\", alpha: 0.65 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 0.9 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 0.85 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 90, color: \"black\", alpha: 1 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tTor: {\n\t\touterBorder:      { lineWidth: 10, radius: 88, color: \"#996600\", alpha: 0.9 },\n\t\tsmallIndicator:   { lineWidth: 6, startAt: -10, endAt: 73, color: \"green\", alpha: 0.3 },\n\t\tlargeIndicator:   { lineWidth: 6, startAt: 73, endAt: 100, color: \"black\", alpha: 0.65 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: -73, endAt: 73, color: \"black\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tCold: {\n\t\touterBorder:      { lineWidth: 15, radius: 90, color: \"black\", alpha: 0.3 },\n\t\tsmallIndicator:   { lineWidth: 15, startAt: -10, endAt: 95, color: \"blue\", alpha: 0.1 },\n\t\tlargeIndicator:   { lineWidth: 3, startAt: 80, endAt: 95, color: \"blue\", alpha: 0.65 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: \"black\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 5, startAt: 30, radius: 10, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tBabosa: {\n\t\touterBorder:      { lineWidth: 100, radius: 25, color: \"blue\", alpha: 0.25 },\n\t\tsmallIndicator:   { lineWidth: 3, startAt: 90, endAt: 95, color: \"#3366CC\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 4, startAt: 75, endAt: 95, color: \"#3366CC\", alpha: 1 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 60, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 85, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 12, startAt: 75, endAt: 90, color: \"red\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: \"black\", color: \"black\", alpha: 1 }\n\t},\n\n\tTumb: {\n\t\touterBorder:      { lineWidth: 105, radius: 5, color: \"green\", alpha: 0.4 },\n\t\tsmallIndicator:   { lineWidth: 1, startAt: 93, endAt: 98, color: \"green\", alpha: 1 },\n\t\tlargeIndicator:   { lineWidth: 50, startAt: 0, endAt: 89, color: \"red\", alpha: 0.14 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: \"black\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: \"black\", color: \"black\", alpha: 0.05 }\n\t},\n\n\tStone: {\n\t\touterBorder:      { lineWidth: 15, radius: 80, color: \"#339933\", alpha: 0.5 },\n\t\tsmallIndicator:   { lineWidth: 2, startAt: 70, endAt: 90, color: \"#FF3300\", alpha: 0.7 },\n\t\tlargeIndicator:   { lineWidth: 15, startAt: 0, endAt: 29, color: \"#FF6600\", alpha: 0.3 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 75, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: \"black\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: \"black\", color: \"black\", alpha: 0.05 }\n\t},\n\n\tDisc: {\n\t\touterBorder:      { lineWidth: 105, radius: 1, color: \"#666600\", alpha: 0.2 },\n\t\tsmallIndicator:   { lineWidth: 1, startAt: 58, endAt: 95, color: \"#669900\", alpha: 0.8 },\n\t\tlargeIndicator:   { lineWidth: 6, startAt: 25, endAt: 35, color: \"#666600\", alpha: 1 },\n\t\thourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: \"black\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 3, startAt: 0, endAt: 75, color: \"black\", alpha: 1 },\n\t\tsecondHand:       { lineWidth: 1, startAt: -75, endAt: 75, color: \"#99CC00\", alpha: 0.8 },\n\t\tsecondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: \"#00FF00\", color: \"green\", alpha: 0.05 }\n\t},\n\n\t// By Yoo Nhe\n\twatermelon: {\n\t\touterBorder:      { lineWidth: 100, radius: 1.7, color: \"#d93d04\", alpha: 5 },\n\t\tsmallIndicator:   { lineWidth: 2, startAt: 50, endAt: 70, color: \"#d93d04\", alpha: 5 },\n\t\tlargeIndicator:   { lineWidth: 2, startAt: 45, endAt: 94, color: \"#a9bf04\", alpha: 1 },\n\t\thourHand:         { lineWidth: 5, startAt: -20, endAt: 80, color: \"#8c0d17\", alpha: 1 },\n\t\tminuteHand:       { lineWidth: 2, startAt: -20, endAt: 80, color: \"#7c8c03\", alpha: .9 },\n\t\tsecondHand:       { lineWidth: 2, startAt: 70, endAt: 94, color: \"#d93d04\", alpha: .85 },\n\t\tsecondDecoration: { lineWidth: 1, startAt: 70, radius: 3, fillColor: \"red\", color: \"black\", alpha: .7 }\n\t}\n};\n"
  },
  {
    "path": "input-scripts/flotr/flotr-0.2.0-alpha.js",
    "content": "//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.\nvar Flotr={version:\"0.2.0-alpha\",author:\"Bas Wenneker\",website:\"http://www.solutoire.com\",_registeredTypes:{lines:\"drawSeriesLines\",points:\"drawSeriesPoints\",bars:\"drawSeriesBars\",candles:\"drawSeriesCandles\",pie:\"drawSeriesPie\"},register:function(A,B){Flotr._registeredTypes[A]=B+\"\"},draw:function(B,D,A,C){C=C||Flotr.Graph;return new C(B,D,A)},getSeries:function(A){return A.collect(function(C){var B,C=(C.data)?Object.clone(C):{data:C};for(B=C.data.length-1;B>-1;--B){C.data[B][1]=(C.data[B][1]===null?null:parseFloat(C.data[B][1]))}return C})},merge:function(D,B){var A=B||{};for(var C in D){A[C]=(D[C]!=null&&typeof (D[C])==\"object\"&&!(D[C].constructor==Array||D[C].constructor==RegExp)&&!Object.isElement(D[C]))?Flotr.merge(D[C],B[C]):A[C]=D[C]}return A},getTickSize:function(E,D,A,B){var H=(A-D)/E;var G=Flotr.getMagnitude(H);var C=H/G;var F=10;if(C<1.5){F=1}else{if(C<2.25){F=2}else{if(C<3){F=((B==0)?2:2.5)}else{if(C<7.5){F=5}}}}return F*G},defaultTickFormatter:function(A){return A+\"\"},defaultTrackFormatter:function(A){return\"(\"+A.x+\", \"+A.y+\")\"},defaultPieLabelFormatter:function(A){return(A.fraction*100).toFixed(2)+\"%\"},getMagnitude:function(A){return Math.pow(10,Math.floor(Math.log(A)/Math.LN10))},toPixel:function(A){return Math.floor(A)+0.5},toRad:function(A){return -A*(Math.PI/180)},parseColor:function(D){if(D instanceof Flotr.Color){return D}var A,C=Flotr.Color;if((A=/rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]))}if((A=/rgba\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]),parseFloat(A[4]))}if((A=/rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55)}if((A=/rgba\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55,parseFloat(A[4]))}if((A=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(D))){return new C(parseInt(A[1],16),parseInt(A[2],16),parseInt(A[3],16))}if((A=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(D))){return new C(parseInt(A[1]+A[1],16),parseInt(A[2]+A[2],16),parseInt(A[3]+A[3],16))}var B=D.strip().toLowerCase();if(B==\"transparent\"){return new C(255,255,255,0)}return((A=C.lookupColors[B]))?new C(A[0],A[1],A[2]):false},extractColor:function(B){var A;do{A=B.getStyle(\"background-color\").toLowerCase();if(!(A==\"\"||A==\"transparent\")){break}B=B.up(0)}while(!B.nodeName.match(/^body$/i));return(A==\"rgba(0, 0, 0, 0)\")?\"transparent\":A}};Flotr.Graph=Class.create({initialize:function(B,C,A){this.el=$(B);if(!this.el){throw\"The target container doesn't exist\"}this.data=C;this.series=Flotr.getSeries(C);this.setOptions(A);this.lastMousePos={pageX:null,pageY:null};this.selection={first:{x:-1,y:-1},second:{x:-1,y:-1}};this.prevSelection=null;this.selectionInterval=null;this.ignoreClick=false;this.prevHit=null;this.constructCanvas();this.initEvents();this.findDataRanges();this.calculateTicks(this.axes.x);this.calculateTicks(this.axes.x2);this.calculateTicks(this.axes.y);this.calculateTicks(this.axes.y2);this.calculateSpacing();this.draw();this.insertLegend();if(this.options.spreadsheet.show){this.constructTabs()}},setOptions:function(B){var P={colors:[\"#00A8F0\",\"#C0D800\",\"#CB4B4B\",\"#4DA74D\",\"#9440ED\"],title:null,subtitle:null,legend:{show:true,noColumns:1,labelFormatter:Prototype.K,labelBoxBorderColor:\"#CCCCCC\",labelBoxWidth:14,labelBoxHeight:10,labelBoxMargin:5,container:null,position:\"nw\",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:0,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},x2axis:{},yaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:90,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},y2axis:{titleAngle:270},points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:\"#FFFFFF\",fillOpacity:0.4},lines:{show:false,lineWidth:2,fill:false,fillColor:null,fillOpacity:0.4},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,horizontal:false,stacked:false},candles:{show:false,lineWidth:1,wickLineWidth:1,candleWidth:0.6,fill:true,upFillColor:\"#00A8F0\",downFillColor:\"#CB4B4B\",fillOpacity:0.5,barcharts:false},pie:{show:false,lineWidth:1,fill:true,fillColor:null,fillOpacity:0.6,explode:6,sizeRatio:0.6,startAngle:Math.PI/4,labelFormatter:Flotr.defaultPieLabelFormatter,pie3D:false,pie3DviewAngle:(Math.PI/2*0.8),pie3DspliceThickness:20},grid:{color:\"#545454\",backgroundColor:null,tickColor:\"#DDDDDD\",labelMargin:3,verticalLines:true,horizontalLines:true,outlineWidth:2},selection:{mode:null,color:\"#B6D9FF\",fps:20},mouse:{track:false,position:\"se\",relative:false,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:\"#FF3F19\",trackDecimals:1,sensibility:2,radius:3},shadowSize:4,defaultType:\"lines\",HtmlText:true,fontSize:7.5,spreadsheet:{show:false,tabGraphLabel:\"Graph\",tabDataLabel:\"Data\",toolbarDownload:\"Download CSV\",toolbarSelectAll:\"Select all\"}};P.x2axis=Object.extend(Object.clone(P.xaxis),P.x2axis);P.y2axis=Object.extend(Object.clone(P.yaxis),P.y2axis);this.options=Flotr.merge((B||{}),P);this.axes={x:{options:this.options.xaxis,n:1},x2:{options:this.options.x2axis,n:2},y:{options:this.options.yaxis,n:1},y2:{options:this.options.y2axis,n:2}};var H=[],C=[],K=this.series.length,N=this.series.length,D=this.options.colors,A=[],G=0,M,J,I,O,E;for(J=N-1;J>-1;--J){M=this.series[J].color;if(M!=null){--N;if(Object.isNumber(M)){H.push(M)}else{A.push(Flotr.parseColor(M))}}}for(J=H.length-1;J>-1;--J){N=Math.max(N,H[J]+1)}for(J=0;C.length<N;){M=(D.length==J)?new Flotr.Color(100,100,100):Flotr.parseColor(D[J]);var F=G%2==1?-1:1;var L=1+F*Math.ceil(G/2)*0.2;M.scale(L,L,L);C.push(M);if(++J>=D.length){J=0;++G}}for(J=0,I=0;J<K;++J){O=this.series[J];if(O.color==null){O.color=C[I++].toString()}else{if(Object.isNumber(O.color)){O.color=C[O.color].toString()}}if(!O.xaxis){O.xaxis=this.axes.x}if(O.xaxis==1){O.xaxis=this.axes.x}else{if(O.xaxis==2){O.xaxis=this.axes.x2}}if(!O.yaxis){O.yaxis=this.axes.y}if(O.yaxis==1){O.yaxis=this.axes.y}else{if(O.yaxis==2){O.yaxis=this.axes.y2}}O.lines=Object.extend(Object.clone(this.options.lines),O.lines);O.points=Object.extend(Object.clone(this.options.points),O.points);O.bars=Object.extend(Object.clone(this.options.bars),O.bars);O.candles=Object.extend(Object.clone(this.options.candles),O.candles);O.pie=Object.extend(Object.clone(this.options.pie),O.pie);O.mouse=Object.extend(Object.clone(this.options.mouse),O.mouse);if(O.shadowSize==null){O.shadowSize=this.options.shadowSize}}},constructCanvas:function(){var C=this.el,B,D,A;this.canvas=C.select(\".flotr-canvas\")[0];this.overlay=C.select(\".flotr-overlay\")[0];C.childElements().invoke(\"remove\");C.setStyle({position:\"relative\",cursor:\"default\"});this.canvasWidth=C.getWidth();this.canvasHeight=C.getHeight();B={width:this.canvasWidth,height:this.canvasHeight};if(this.canvasWidth<=0||this.canvasHeight<=0){throw\"Invalid dimensions for plot, width = \"+this.canvasWidth+\", height = \"+this.canvasHeight}if(!this.canvas){D=this.canvas=new Element(\"canvas\",B);D.className=\"flotr-canvas\";D=D.writeAttribute(\"style\",\"position:absolute;left:0px;top:0px;\")}else{D=this.canvas.writeAttribute(B)}C.insert(D);if(Prototype.Browser.IE){D=window.G_vmlCanvasManager.initElement(D)}this.ctx=D.getContext(\"2d\");if(!this.overlay){A=this.overlay=new Element(\"canvas\",B);A.className=\"flotr-overlay\";A=A.writeAttribute(\"style\",\"position:absolute;left:0px;top:0px;\")}else{A=this.overlay.writeAttribute(B)}C.insert(A);if(Prototype.Browser.IE){A=window.G_vmlCanvasManager.initElement(A)}this.octx=A.getContext(\"2d\");if(window.CanvasText){CanvasText.enable(this.ctx);CanvasText.enable(this.octx);this.textEnabled=true}},getTextDimensions:function(F,C,B,D){if(!F){return{width:0,height:0}}if(!this.options.HtmlText&&this.textEnabled){var E=this.ctx.getTextBounds(F,C);return{width:E.width+2,height:E.height+6}}else{var A=this.el.insert('<div style=\"position:absolute;top:-10000px;'+B+'\" class=\"'+D+' flotr-dummy-div\">'+F+\"</div>\").select(\".flotr-dummy-div\")[0];dim=A.getDimensions();A.remove();return dim}},loadDataGrid:function(){if(this.seriesData){return this.seriesData}var A=this.series;var B=[];for(i=0;i<A.length;++i){A[i].data.each(function(D){var C=D[0],F=D[1];if(r=B.find(function(G){return G[0]==C})){r[i+1]=F}else{var E=[];E[0]=C;E[i+1]=F;B.push(E)}})}B=B.sortBy(function(C){return C[0]});return this.seriesData=B},showTab:function(B,C){var A=\"canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle\";switch(B){case\"graph\":this.datagrid.up().hide();this.el.select(A).invoke(\"show\");this.tabs.data.removeClassName(\"selected\");this.tabs.graph.addClassName(\"selected\");break;case\"data\":this.constructDataGrid();this.datagrid.up().show();this.el.select(A).invoke(\"hide\");this.tabs.data.addClassName(\"selected\");this.tabs.graph.removeClassName(\"selected\");break}},constructTabs:function(){var A=new Element(\"div\",{className:\"flotr-tabs-group\",style:\"position:absolute;left:0px;top:\"+this.canvasHeight+\"px;width:\"+this.canvasWidth+\"px;\"});this.el.insert({bottom:A});this.tabs={graph:new Element(\"div\",{className:\"flotr-tab selected\",style:\"float:left;\"}).update(this.options.spreadsheet.tabGraphLabel),data:new Element(\"div\",{className:\"flotr-tab\",style:\"float:left;\"}).update(this.options.spreadsheet.tabDataLabel)};A.insert(this.tabs.graph).insert(this.tabs.data);this.el.setStyle({height:this.canvasHeight+this.tabs.data.getHeight()+2+\"px\"});this.tabs.graph.observe(\"click\",(function(){this.showTab(\"graph\")}).bind(this));this.tabs.data.observe(\"click\",(function(){this.showTab(\"data\")}).bind(this))},constructDataGrid:function(){if(this.datagrid){return this.datagrid}var D,B,L=this.series,J=this.loadDataGrid();var K=this.datagrid=new Element(\"table\",{className:\"flotr-datagrid\",style:\"height:100px;\"});var C=[\"<colgroup><col />\"];var F=['<tr class=\"first-row\">'];F.push(\"<th>&nbsp;</th>\");for(D=0;D<L.length;++D){F.push('<th scope=\"col\">'+(L[D].label||String.fromCharCode(65+D))+\"</th>\");C.push(\"<col />\")}F.push(\"</tr>\");for(B=0;B<J.length;++B){F.push(\"<tr>\");for(D=0;D<L.length+1;++D){var M=\"td\";var G=(J[B][D]!=null?Math.round(J[B][D]*100000)/100000:\"\");if(D==0){M=\"th\";var I;if(this.options.xaxis.ticks){var E=this.options.xaxis.ticks.find(function(N){return N[0]==J[B][D]});if(E){I=E[1]}}else{I=this.options.xaxis.tickFormatter(G)}if(I){G=I}}F.push(\"<\"+M+(M==\"th\"?' scope=\"row\"':\"\")+\">\"+G+\"</\"+M+\">\")}F.push(\"</tr>\")}C.push(\"</colgroup>\");K.update(C.join(\"\")+F.join(\"\"));if(!Prototype.Browser.IE){K.select(\"td\").each(function(N){N.observe(\"mouseover\",function(O){N=O.element();var P=N.previousSiblings();K.select(\"th[scope=col]\")[P.length-1].addClassName(\"hover\");K.select(\"colgroup col\")[P.length].addClassName(\"hover\")});N.observe(\"mouseout\",function(){K.select(\"colgroup col.hover, th.hover\").each(function(O){O.removeClassName(\"hover\")})})})}var H=new Element(\"div\",{className:\"flotr-datagrid-toolbar\"}).insert(new Element(\"button\",{type:\"button\",className:\"flotr-datagrid-toolbar-button\"}).update(this.options.spreadsheet.toolbarDownload).observe(\"click\",this.downloadCSV.bind(this))).insert(new Element(\"button\",{type:\"button\",className:\"flotr-datagrid-toolbar-button\"}).update(this.options.spreadsheet.toolbarSelectAll).observe(\"click\",this.selectAllData.bind(this)));var A=new Element(\"div\",{className:\"flotr-datagrid-container\",style:\"left:0px;top:0px;width:\"+this.canvasWidth+\"px;height:\"+this.canvasHeight+\"px;overflow:auto;\"});A.insert(H);K.wrap(A.hide());this.el.insert(A);return K},selectAllData:function(){if(this.tabs){var B,A,E,D,C=this.constructDataGrid();this.showTab(\"data\");(function(){if((E=C.ownerDocument)&&(D=E.defaultView)&&D.getSelection&&E.createRange&&(B=window.getSelection())&&B.removeAllRanges){A=E.createRange();A.selectNode(C);B.removeAllRanges();B.addRange(A)}else{if(document.body&&document.body.createTextRange&&(A=document.body.createTextRange())){A.moveToElementText(C);A.select()}}}).defer();return true}else{return false}},downloadCSV:function(){var D,A='\"x\"',C=this.series,E=this.loadDataGrid();for(D=0;D<C.length;++D){A+='%09\"'+(C[D].label||String.fromCharCode(65+D))+'\"'}A+=\"%0D%0A\";for(D=0;D<E.length;++D){if(this.options.xaxis.ticks){var B=this.options.xaxis.ticks.find(function(F){return F[0]==E[D][0]});if(B){E[D][0]=B[1]}}else{E[D][0]=this.options.xaxis.tickFormatter(E[D][0])}A+=E[D].join(\"%09\")+\"%0D%0A\"}if(Prototype.Browser.IE){A=A.gsub(\"%09\",\"\\t\").gsub(\"%0A\",\"\\n\").gsub(\"%0D\",\"\\r\");window.open().document.write(A)}else{window.open(\"data:text/csv,\"+A)}},initEvents:function(){this.overlay.stopObserving();this.overlay.observe(\"mousedown\",this.mouseDownHandler.bind(this));this.overlay.observe(\"mousemove\",this.mouseMoveHandler.bind(this));this.overlay.observe(\"click\",this.clickHandler.bind(this))},findDataRanges:function(){var J=this.series,G=this.axes;G.x.datamin=0;G.x.datamax=0;G.x2.datamin=0;G.x2.datamax=0;G.y.datamin=0;G.y.datamax=0;G.y2.datamin=0;G.y2.datamax=0;if(J.length>0){var C,A,D,H,F,B,I,E;for(C=0;C<J.length;++C){B=J[C].data,I=J[C].xaxis,E=J[C].yaxis;if(B.length>0&&!J[C].hide){if(!I.used){I.datamin=I.datamax=B[0][0]}if(!E.used){E.datamin=E.datamax=B[0][1]}I.used=true;E.used=true;for(D=B.length-1;D>-1;--D){H=B[D][0];if(H<I.datamin){I.datamin=H}else{if(H>I.datamax){I.datamax=H}}for(A=1;A<B[D].length;A++){F=B[D][A];if(F<E.datamin){E.datamin=F}else{if(F>E.datamax){E.datamax=F}}}}}}}this.findXAxesValues();this.calculateRange(G.x);this.extendXRangeIfNeededByBar(G.x);if(G.x2.used){this.calculateRange(G.x2);this.extendXRangeIfNeededByBar(G.x2)}this.calculateRange(G.y);this.extendYRangeIfNeededByBar(G.y);if(G.y2.used){this.calculateRange(G.y2);this.extendYRangeIfNeededByBar(G.y2)}},calculateRange:function(D){var F=D.options,C=F.min!=null?F.min:D.datamin,A=F.max!=null?F.max:D.datamax,E;if(A-C==0){var B=(A==0)?1:0.01;C-=B;A+=B}D.tickSize=Flotr.getTickSize(F.noTicks,C,A,F.tickDecimals);if(F.min==null){E=F.autoscaleMargin;if(E!=0){C-=D.tickSize*E;if(C<0&&D.datamin>=0){C=0}C=D.tickSize*Math.floor(C/D.tickSize)}}if(F.max==null){E=F.autoscaleMargin;if(E!=0){A+=D.tickSize*E;if(A>0&&D.datamax<=0){A=0}A=D.tickSize*Math.ceil(A/D.tickSize)}}D.min=C;D.max=A},extendXRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.axis==A&&(F.show||E.show)){if(!F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+I.bars.barWidth}if(F.stacked&&F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},extendYRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.yaxis==A&&F.show&&!I.hide){if(F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+F.barWidth}if(F.stacked&&!F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},findXAxesValues:function(){for(i=this.series.length-1;i>-1;--i){s=this.series[i];s.xaxis.values=s.xaxis.values||[];for(j=s.data.length-1;j>-1;--j){s.xaxis.values[s.data[j][0]]={}}}},calculateTicks:function(D){var B=D.options,E,H;D.ticks=[];if(B.ticks){var G=B.ticks,I,F;if(Object.isFunction(G)){G=G({min:D.min,max:D.max})}for(E=0;E<G.length;++E){I=G[E];if(typeof (I)==\"object\"){H=I[0];F=(I.length>1)?I[1]:B.tickFormatter(H)}else{H=I;F=B.tickFormatter(H)}D.ticks[E]={v:H,label:F}}}else{var A=D.tickSize*Math.ceil(D.min/D.tickSize),C;for(E=0;A+E*D.tickSize<=D.max;++E){H=A+E*D.tickSize;C=B.tickDecimals;if(C==null){C=1-Math.floor(Math.log(D.tickSize)/Math.LN10)}if(C<0){C=0}H=H.toFixed(C);D.ticks.push({v:H,label:B.tickFormatter(H)})}}},calculateSpacing:function(){var L=this.axes,N=this.options,H=this.series,D=N.grid.labelMargin,M=L.x,A=L.x2,J=L.y,K=L.y2,F=2,G,E,C,I;[M,A,J,K].each(function(P){var O=\"\";if(P.options.showLabels){for(G=0;G<P.ticks.length;++G){C=P.ticks[G].label.length;if(C>O.length){O=P.ticks[G].label}}}P.maxLabel=this.getTextDimensions(O,{size:N.fontSize,angle:Flotr.toRad(P.options.labelsAngle)},\"font-size:smaller;\",\"flotr-grid-label\");P.titleSize=this.getTextDimensions(P.options.title,{size:N.fontSize*1.2,angle:Flotr.toRad(P.options.titleAngle)},\"font-weight:bold;\",\"flotr-axis-title\")},this);I=this.getTextDimensions(N.title,{size:N.fontSize*1.5},\"font-size:1em;font-weight:bold;\",\"flotr-title\");this.titleHeight=I.height;I=this.getTextDimensions(N.subtitle,{size:N.fontSize},\"font-size:smaller;\",\"flotr-subtitle\");this.subtitleHeight=I.height;if(N.show){F=Math.max(F,N.points.radius+N.points.lineWidth/2)}for(E=0;E<N.length;++E){if(H[E].points.show){F=Math.max(F,H[E].points.radius+H[E].points.lineWidth/2)}}var B=this.plotOffset={left:0,right:0,top:0,bottom:0};B.left=B.right=B.top=B.bottom=F;B.bottom+=(M.options.showLabels?(M.maxLabel.height+D):0)+(M.options.title?(M.titleSize.height+D):0);B.top+=(A.options.showLabels?(A.maxLabel.height+D):0)+(A.options.title?(A.titleSize.height+D):0)+this.subtitleHeight+this.titleHeight;B.left+=(J.options.showLabels?(J.maxLabel.width+D):0)+(J.options.title?(J.titleSize.width+D):0);B.right+=(K.options.showLabels?(K.maxLabel.width+D):0)+(K.options.title?(K.titleSize.width+D):0);B.top=Math.floor(B.top);this.plotWidth=this.canvasWidth-B.left-B.right;this.plotHeight=this.canvasHeight-B.bottom-B.top;M.scale=this.plotWidth/(M.max-M.min);A.scale=this.plotWidth/(A.max-A.min);J.scale=this.plotHeight/(J.max-J.min);K.scale=this.plotHeight/(K.max-K.min)},draw:function(){this.drawGrid();this.drawLabels();this.drawTitles();if(this.series.length){this.el.fire(\"flotr:beforedraw\",[this.series,this]);for(var A=0;A<this.series.length;A++){if(!this.series[A].hide){this.drawSeries(this.series[A])}}}this.el.fire(\"flotr:afterdraw\",[this.series,this])},tHoz:function(A,B){B=B||this.axes.x;return(A-B.min)*B.scale},tVert:function(B,A){A=A||this.axes.y;return this.plotHeight-(B-A.min)*A.scale},drawGrid:function(){var B,E=this.options,A=this.ctx;if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire(\"flotr:beforegrid\",[this.axes.x,this.axes.y,E,this])}A.save();A.translate(this.plotOffset.left,this.plotOffset.top);if(E.grid.backgroundColor!=null){A.fillStyle=E.grid.backgroundColor;A.fillRect(0,0,this.plotWidth,this.plotHeight)}A.lineWidth=1;A.strokeStyle=E.grid.tickColor;A.beginPath();if(E.grid.verticalLines){for(var D=0;D<this.axes.x.ticks.length;++D){B=this.axes.x.ticks[D].v;if((B==this.axes.x.min||B==this.axes.x.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(Math.floor(this.tHoz(B))+A.lineWidth/2,0);A.lineTo(Math.floor(this.tHoz(B))+A.lineWidth/2,this.plotHeight)}}if(E.grid.horizontalLines){for(var C=0;C<this.axes.y.ticks.length;++C){B=this.axes.y.ticks[C].v;if((B==this.axes.y.min||B==this.axes.y.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(0,Math.floor(this.tVert(B))+A.lineWidth/2);A.lineTo(this.plotWidth,Math.floor(this.tVert(B))+A.lineWidth/2)}}A.stroke();if(E.grid.outlineWidth!=0){A.lineWidth=E.grid.outlineWidth;A.strokeStyle=E.grid.color;A.lineJoin=\"round\";A.strokeRect(0,0,this.plotWidth,this.plotHeight)}A.restore();if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire(\"flotr:aftergrid\",[this.axes.x,this.axes.y,E,this])}},drawLabels:function(){var C=0,D,B,E,F,G,J=this.options,I=this.ctx,H=this.axes;for(E=0;E<H.x.ticks.length;++E){if(H.x.ticks[E].label){++C}}B=this.plotWidth/C;if(!J.HtmlText&&this.textEnabled){var A={size:J.fontSize,adjustAlign:true};D=H.x;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign=\"c\";A.valign=\"t\";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+this.plotHeight+J.grid.labelMargin,A)}D=H.x2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign=\"c\";A.valign=\"b\";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+J.grid.labelMargin,A)}D=H.y;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign=\"r\";A.valign=\"m\";I.drawText(G.label,this.plotOffset.left-J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A)}D=H.y2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign=\"l\";A.valign=\"m\";I.drawText(G.label,this.plotOffset.left+this.plotWidth+J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A);I.save();I.strokeStyle=A.color;I.beginPath();I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D));I.stroke();I.restore()}}else{if(H.x.options.showLabels||H.x2.options.showLabels||H.y.options.showLabels||H.y2.options.showLabels){F=['<div style=\"font-size:smaller;color:'+J.grid.color+';\" class=\"flotr-labels\">'];D=H.x;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.plotHeight+J.grid.labelMargin)+\"px;left:\"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+\"px;width:\"+B+\"px;text-align:center;\"+(D.options.color?(\"color:\"+D.options.color+\";\"):\"\")+'\" class=\"flotr-grid-label\">'+G.label+\"</div>\")}}D=H.x2;if(D.options.showLabels&&D.used){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style=\"position:absolute;top:'+(this.plotOffset.top-J.grid.labelMargin-D.maxLabel.height)+\"px;left:\"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+\"px;width:\"+B+\"px;text-align:center;\"+(D.options.color?(\"color:\"+D.options.color+\";\"):\"\")+'\" class=\"flotr-grid-label\">'+G.label+\"</div>\")}}D=H.y;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+\"px;left:0;width:\"+(this.plotOffset.left-J.grid.labelMargin)+\"px;text-align:right;\"+(D.options.color?(\"color:\"+D.options.color+\";\"):\"\")+'\" class=\"flotr-grid-label\">'+G.label+\"</div>\")}}D=H.y2;if(D.options.showLabels&&D.used){I.save();I.strokeStyle=D.options.color||J.grid.color;I.beginPath();for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+\"px;right:0;width:\"+(this.plotOffset.right-J.grid.labelMargin)+\"px;text-align:left;\"+(D.options.color?(\"color:\"+D.options.color+\";\"):\"\")+'\" class=\"flotr-grid-label\">'+G.label+\"</div>\");I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D))}I.stroke();I.restore()}F.push(\"</div>\");this.el.insert(F.join(\"\"))}}},drawTitles:function(){var D,C=this.options,F=C.grid.labelMargin,B=this.ctx,A=this.axes;if(!C.HtmlText&&this.textEnabled){var E={size:C.fontSize,color:C.grid.color,halign:\"c\"};if(C.subtitle){B.drawText(C.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,E)}E.weight=1.5;E.size*=1.5;if(C.title){B.drawText(C.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,E)}E.weight=1.8;E.size*=0.8;E.adjustAlign=true;if(A.x.options.title&&A.x.used){E.halign=\"c\";E.valign=\"t\";E.angle=Flotr.toRad(A.x.options.titleAngle);B.drawText(A.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+A.x.maxLabel.height+this.plotHeight+2*F,E)}if(A.x2.options.title&&A.x2.used){E.halign=\"c\";E.valign=\"b\";E.angle=Flotr.toRad(A.x2.options.titleAngle);B.drawText(A.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-A.x2.maxLabel.height-2*F,E)}if(A.y.options.title&&A.y.used){E.halign=\"r\";E.valign=\"m\";E.angle=Flotr.toRad(A.y.options.titleAngle);B.drawText(A.y.options.title,this.plotOffset.left-A.y.maxLabel.width-2*F,this.plotOffset.top+this.plotHeight/2,E)}if(A.y2.options.title&&A.y2.used){E.halign=\"l\";E.valign=\"m\";E.angle=Flotr.toRad(A.y2.options.titleAngle);B.drawText(A.y2.options.title,this.plotOffset.left+this.plotWidth+A.y2.maxLabel.width+2*F,this.plotOffset.top+this.plotHeight/2,E)}}else{D=['<div style=\"color:'+C.grid.color+';\" class=\"flotr-titles\">'];if(C.title){D.push('<div style=\"position:absolute;top:0;left:'+this.plotOffset.left+\"px;font-size:1em;font-weight:bold;text-align:center;width:\"+this.plotWidth+'px;\" class=\"flotr-title\">'+C.title+\"</div>\")}if(C.subtitle){D.push('<div style=\"position:absolute;top:'+this.titleHeight+\"px;left:\"+this.plotOffset.left+\"px;font-size:smaller;text-align:center;width:\"+this.plotWidth+'px;\" class=\"flotr-subtitle\">'+C.subtitle+\"</div>\")}D.push(\"</div>\");D.push('<div class=\"flotr-axis-title\" style=\"font-weight:bold;\">');if(A.x.options.title&&A.x.used){D.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.plotHeight+C.grid.labelMargin+A.x.titleSize.height)+\"px;left:\"+this.plotOffset.left+\"px;width:\"+this.plotWidth+'px;text-align:center;\" class=\"flotr-axis-title\">'+A.x.options.title+\"</div>\")}if(A.x2.options.title&&A.x2.used){D.push('<div style=\"position:absolute;top:0;left:'+this.plotOffset.left+\"px;width:\"+this.plotWidth+'px;text-align:center;\" class=\"flotr-axis-title\">'+A.x2.options.title+\"</div>\")}if(A.y.options.title&&A.y.used){D.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;left:0;text-align:right;\" class=\"flotr-axis-title\">'+A.y.options.title+\"</div>\")}if(A.y2.options.title&&A.y2.used){D.push('<div style=\"position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;right:0;text-align:right;\" class=\"flotr-axis-title\">'+A.y2.options.title+\"</div>\")}D.push(\"</div>\");this.el.insert(D.join(\"\"))}},drawSeries:function(A){A=A||this.series;var C=false;for(var B in Flotr._registeredTypes){if(A[B]&&A[B].show){this[Flotr._registeredTypes[B]](A);C=true}}if(!C){this[Flotr._registeredTypes[this.options.defaultType]](A)}},plotLine:function(I,F){var O=this.ctx,A=I.xaxis,K=I.yaxis,J=this.tHoz.bind(this),M=this.tVert.bind(this),H=I.data;if(H.length<2){return }var E=J(H[0][0],A),D=M(H[0][1],K)+F;O.beginPath();O.moveTo(E,D);for(var G=0;G<H.length-1;++G){var C=H[G][0],N=H[G][1],B=H[G+1][0],L=H[G+1][1];if(N===null||L===null){continue}if(N<=L&&N<K.min){if(L<K.min){continue}C=(K.min-N)/(L-N)*(B-C)+C;N=K.min}else{if(L<=N&&L<K.min){if(N<K.min){continue}B=(K.min-N)/(L-N)*(B-C)+C;L=K.min}}if(N>=L&&N>K.max){if(L>K.max){continue}C=(K.max-N)/(L-N)*(B-C)+C;N=K.max}else{if(L>=N&&L>K.max){if(N>K.max){continue}B=(K.max-N)/(L-N)*(B-C)+C;L=K.max}}if(C<=B&&C<A.min){if(B<A.min){continue}N=(A.min-C)/(B-C)*(L-N)+N;C=A.min}else{if(B<=C&&B<A.min){if(C<A.min){continue}L=(A.min-C)/(B-C)*(L-N)+N;B=A.min}}if(C>=B&&C>A.max){if(B>A.max){continue}N=(A.max-C)/(B-C)*(L-N)+N;C=A.max}else{if(B>=C&&B>A.max){if(C>A.max){continue}L=(A.max-C)/(B-C)*(L-N)+N;B=A.max}}if(E!=J(C,A)||D!=M(N,K)+F){O.moveTo(J(C,A),M(N,K)+F)}E=J(B,A);D=M(L,K)+F;O.lineTo(E,D)}O.stroke()},plotLineArea:function(J,D){var S=J.data;if(S.length<2){return }var L,G=0,N=this.ctx,Q=J.xaxis,B=J.yaxis,E=this.tHoz.bind(this),M=this.tVert.bind(this),H=Math.min(Math.max(0,B.min),B.max),F=true;N.beginPath();for(var O=0;O<S.length-1;++O){var R=S[O][0],C=S[O][1],P=S[O+1][0],A=S[O+1][1];if(R<=P&&R<Q.min){if(P<Q.min){continue}C=(Q.min-R)/(P-R)*(A-C)+C;R=Q.min}else{if(P<=R&&P<Q.min){if(R<Q.min){continue}A=(Q.min-R)/(P-R)*(A-C)+C;P=Q.min}}if(R>=P&&R>Q.max){if(P>Q.max){continue}C=(Q.max-R)/(P-R)*(A-C)+C;R=Q.max}else{if(P>=R&&P>Q.max){if(R>Q.max){continue}A=(Q.max-R)/(P-R)*(A-C)+C;P=Q.max}}if(F){N.moveTo(E(R,Q),M(H,B)+D);F=false}if(C>=B.max&&A>=B.max){N.lineTo(E(R,Q),M(B.max,B)+D);N.lineTo(E(P,Q),M(B.max,B)+D);continue}else{if(C<=B.min&&A<=B.min){N.lineTo(E(R,Q),M(B.min,B)+D);N.lineTo(E(P,Q),M(B.min,B)+D);continue}}var I=R,K=P;if(C<=A&&C<B.min&&A>=B.min){R=(B.min-C)/(A-C)*(P-R)+R;C=B.min}else{if(A<=C&&A<B.min&&C>=B.min){P=(B.min-C)/(A-C)*(P-R)+R;A=B.min}}if(C>=A&&C>B.max&&A<=B.max){R=(B.max-C)/(A-C)*(P-R)+R;C=B.max}else{if(A>=C&&A>B.max&&C<=B.max){P=(B.max-C)/(A-C)*(P-R)+R;A=B.max}}if(R!=I){L=(C<=B.min)?L=B.min:B.max;N.lineTo(E(I,Q),M(L,B)+D);N.lineTo(E(R,Q),M(L,B)+D)}N.lineTo(E(R,Q),M(C,B)+D);N.lineTo(E(P,Q),M(A,B)+D);if(P!=K){L=(A<=B.min)?B.min:B.max;N.lineTo(E(K,Q),M(L,B)+D);N.lineTo(E(P,Q),M(L,B)+D)}G=Math.max(P,K)}N.lineTo(E(G,Q),M(H,B)+D);N.closePath();N.fill()},drawSeriesLines:function(C){C=C||this.series;var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);B.lineJoin=\"round\";var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;var E=D/2+B.lineWidth/2;B.strokeStyle=\"rgba(0,0,0,0.1)\";this.plotLine(C,E+A/2);B.strokeStyle=\"rgba(0,0,0,0.2)\";this.plotLine(C,E);if(C.lines.fill){B.fillStyle=\"rgba(0,0,0,0.05)\";this.plotLineArea(C,E+A/2)}}B.lineWidth=D;B.strokeStyle=C.color;if(C.lines.fill){B.fillStyle=C.lines.fillColor!=null?C.lines.fillColor:Flotr.parseColor(C.color).scale(null,null,null,C.lines.fillOpacity).toString();this.plotLineArea(C,0)}this.plotLine(C,0);B.restore()},drawSeriesPoints:function(C){var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;B.strokeStyle=\"rgba(0,0,0,0.1)\";this.plotPointShadows(C,A/2+B.lineWidth/2,C.points.radius);B.strokeStyle=\"rgba(0,0,0,0.2)\";this.plotPointShadows(C,B.lineWidth/2,C.points.radius)}B.lineWidth=C.points.lineWidth;B.strokeStyle=C.color;B.fillStyle=C.points.fillColor!=null?C.points.fillColor:C.color;this.plotPoints(C,C.points.radius,C.points.fill);B.restore()},plotPoints:function(C,E,I){var A=C.xaxis,F=C.yaxis,J=this.ctx,D,B=C.data;for(D=B.length-1;D>-1;--D){var H=B[D][0],G=B[D][1];if(H<A.min||H>A.max||G<F.min||G>F.max){continue}J.beginPath();J.arc(this.tHoz(H,A),this.tVert(G,F),E,0,2*Math.PI,true);if(I){J.fill()}J.stroke()}},plotPointShadows:function(D,B,F){var A=D.xaxis,G=D.yaxis,J=this.ctx,E,C=D.data;for(E=C.length-1;E>-1;--E){var I=C[E][0],H=C[E][1];if(I<A.min||I>A.max||H<G.min||H>G.max){continue}J.beginPath();J.arc(this.tHoz(I,A),this.tVert(H,G)+B,F,0,Math.PI,false);J.stroke()}},drawSeriesBars:function(B){var A=this.ctx,D=B.bars.barWidth,C=Math.min(B.bars.lineWidth,D);A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin=\"miter\";A.lineWidth=C;A.strokeStyle=B.color;this.plotBarsShadows(B,D,0,B.bars.fill);if(B.bars.fill){A.fillStyle=B.bars.fillColor!=null?B.bars.fillColor:Flotr.parseColor(B.color).scale(null,null,null,B.bars.fillOpacity).toString()}this.plotBars(B,D,0,B.bars.fill);A.restore()},plotBars:function(K,N,D,Q){var U=K.data;if(U.length<1){return }var S=K.xaxis,B=K.yaxis,P=this.ctx,F=this.tHoz.bind(this),O=this.tVert.bind(this);for(var R=0;R<U.length;R++){var J=U[R][0],I=U[R][1];var E=true,L=true,A=true;var H=0;if(K.bars.stacked){S.values.each(function(W,V){if(V==J){H=W.stack||0;W.stack=H+I}})}if(K.bars.horizontal){var C=H,T=J+H,G=I,M=I+N}else{var C=J,T=J+N,G=H,M=I+H}if(T<S.min||C>S.max||M<B.min||G>B.max){continue}if(C<S.min){C=S.min;E=false}if(T>S.max){T=S.max;if(S.lastSerie!=K&&K.bars.horizontal){L=false}}if(G<B.min){G=B.min}if(M>B.max){M=B.max;if(B.lastSerie!=K&&!K.bars.horizontal){L=false}}if(Q){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P.lineTo(F(C,S),O(M,B)+D);P.lineTo(F(T,S),O(M,B)+D);P.lineTo(F(T,S),O(G,B)+D);P.fill()}if(K.bars.lineWidth!=0&&(E||A||L)){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P[E?\"lineTo\":\"moveTo\"](F(C,S),O(M,B)+D);P[L?\"lineTo\":\"moveTo\"](F(T,S),O(M,B)+D);P[A?\"lineTo\":\"moveTo\"](F(T,S),O(G,B)+D);P.stroke()}}},plotBarsShadows:function(I,K,C){var T=I.data;if(T.length<1){return }var R=I.xaxis,A=I.yaxis,P=this.ctx,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var Q=0;Q<T.length;Q++){var H=T[Q][0],G=T[Q][1];var E=0;if(I.bars.stacked){R.values.each(function(V,U){if(U==H){E=V.stackShadow||0;V.stackShadow=E+G}})}if(I.bars.horizontal){var B=E,S=H+E,F=G,J=G+K}else{var B=H,S=H+K,F=E,J=G+E}if(S<R.min||B>R.max||J<A.min||F>A.max){continue}if(B<R.min){B=R.min}if(S>R.max){S=R.max}if(F<A.min){F=A.min}if(J>A.max){J=A.max}var O=D(S,R)-D(B,R)-((D(S,R)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(F,A)-M(J,A)-((M(F,A)+N<=this.plotHeight)?0:N));P.fillStyle=\"rgba(0,0,0,0.05)\";P.fillRect(Math.min(D(B,R)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesCandles:function(B){var A=this.ctx,C=B.candles.candleWidth;A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin=\"miter\";A.lineWidth=B.candles.lineWidth;this.plotCandlesShadows(B,C/2);this.plotCandles(B,C/2);A.restore()},plotCandles:function(K,D){var W=K.data;if(W.length<1){return }var T=K.xaxis,B=K.yaxis,P=this.ctx,E=this.tHoz.bind(this),O=this.tVert.bind(this);for(var S=0;S<W.length;S++){var U=W[S],J=U[0],L=U[1],I=U[2],X=U[3],N=U[4];var C=J,V=J+K.candles.candleWidth,G=Math.max(B.min,X),M=Math.min(B.max,I),A=Math.max(B.min,Math.min(L,N)),R=Math.min(B.max,Math.max(L,N));if(V<T.min||C>T.max||M<B.min||G>B.max){continue}var Q=K.candles[L>N?\"downFillColor\":\"upFillColor\"];if(K.candles.fill&&!K.candles.barcharts){P.fillStyle=Flotr.parseColor(Q).scale(null,null,null,K.candles.fillOpacity).toString();P.fillRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B))}if(K.candles.lineWidth||K.candles.wickLineWidth){var J,H,F=(K.candles.wickLineWidth%2)/2;J=Math.floor(E((C+V)/2),T)+F;P.save();P.strokeStyle=Q;P.lineWidth=K.candles.wickLineWidth;P.lineCap=\"butt\";if(K.candles.barcharts){P.beginPath();P.moveTo(J,Math.floor(O(M,B)+D));P.lineTo(J,Math.floor(O(G,B)+D));H=Math.floor(O(L,B)+D)+0.5;P.moveTo(Math.floor(E(C,T))+F,H);P.lineTo(J,H);H=Math.floor(O(N,B)+D)+0.5;P.moveTo(Math.floor(E(V,T))+F,H);P.lineTo(J,H)}else{P.strokeRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B));P.beginPath();P.moveTo(J,Math.floor(O(R,B)+D));P.lineTo(J,Math.floor(O(M,B)+D));P.moveTo(J,Math.floor(O(A,B)+D));P.lineTo(J,Math.floor(O(G,B)+D))}P.stroke();P.restore()}}},plotCandlesShadows:function(H,C){var T=H.data;if(T.length<1||H.candles.barcharts){return }var Q=H.xaxis,A=H.yaxis,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var P=0;P<T.length;P++){var R=T[P],G=R[0],I=R[1],F=R[2],U=R[3],K=R[4];var B=G,S=G+H.candles.candleWidth,E=Math.max(A.min,Math.min(I,K)),J=Math.min(A.max,Math.max(I,K));if(S<Q.min||B>Q.max||J<A.min||E>A.max){continue}var O=D(S,Q)-D(B,Q)-((D(S,Q)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(E,A)-M(J,A)-((M(E,A)+N<=this.plotHeight)?0:N));this.ctx.fillStyle=\"rgba(0,0,0,0.05)\";this.ctx.fillRect(Math.min(D(B,Q)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesPie:function(G){if(!this.options.pie.drawn){var K=this.ctx,C=this.options,E=G.pie.lineWidth,I=G.shadowSize,R=G.data,D=(Math.min(this.canvasWidth,this.canvasHeight)*G.pie.sizeRatio)/2,H=[];var L=1;var P=Math.sin(G.pie.viewAngle)*G.pie.spliceThickness/L;var M={size:C.fontSize*1.2,color:C.grid.color,weight:1.5};var Q={x:(this.canvasWidth+this.plotOffset.left)/2,y:(this.canvasHeight-this.plotOffset.bottom)/2};var O=this.series.collect(function(T,S){if(T.pie.show){return{name:(T.label||T.data[0][1]),value:[S,T.data[0][1]],explode:T.pie.explode}}});var B=O.pluck(\"value\").pluck(1).inject(0,function(S,T){return S+T});var F=0,N=G.pie.startAngle,J=0;var A=O.collect(function(S){N+=F;J=parseFloat(S.value[1]);F=J/B;return{name:S.name,fraction:F,x:S.value[0],y:J,explode:S.explode,startAngle:2*N*Math.PI,endAngle:2*(N+F)*Math.PI}});K.save();if(I>0){A.each(function(V){var S=(V.startAngle+V.endAngle)/2;var T=Q.x+Math.cos(S)*V.explode+I;var U=Q.y+Math.sin(S)*V.explode+I;this.plotSlice(T,U,D,V.startAngle,V.endAngle,false,L);K.fillStyle=\"rgba(0,0,0,0.1)\";K.fill()},this)}if(C.HtmlText){H=['<div style=\"color:'+this.options.grid.color+'\" class=\"flotr-labels\">']}A.each(function(c,X){var W=(c.startAngle+c.endAngle)/2;var V=C.colors[X];var Y=Q.x+Math.cos(W)*c.explode;var U=Q.y+Math.sin(W)*c.explode;this.plotSlice(Y,U,D,c.startAngle,c.endAngle,false,L);if(G.pie.fill){K.fillStyle=Flotr.parseColor(V).scale(null,null,null,G.pie.fillOpacity).toString();K.fill()}K.lineWidth=E;K.strokeStyle=V;K.stroke();var b=C.pie.labelFormatter(c);var S=(Math.cos(W)<0);var a=Y+Math.cos(W)*(G.pie.explode+D);var Z=U+Math.sin(W)*(G.pie.explode+D);if(c.fraction&&b){if(C.HtmlText){var T=\"position:absolute;top:\"+(Z-5)+\"px;\";if(S){T+=\"right:\"+(this.canvasWidth-a)+\"px;text-align:right;\"}else{T+=\"left:\"+a+\"px;text-align:left;\"}H.push('<div style=\"'+T+'\" class=\"flotr-grid-label\">'+b+\"</div>\")}else{M.halign=S?\"r\":\"l\";K.drawText(b,a,Z+M.size/2,M)}}},this);if(C.HtmlText){H.push(\"</div>\");this.el.insert(H.join(\"\"))}K.restore();C.pie.drawn=true}},plotSlice:function(B,H,A,E,D,F,G){var C=this.ctx;G=G||1;C.save();C.scale(1,G);C.beginPath();C.moveTo(B,H);C.arc(B,H,A,E,D,F);C.lineTo(B,H);C.closePath();C.restore()},plotPie:function(){},insertLegend:function(){if(!this.options.legend.show){return }var H=this.series,I=this.plotOffset,B=this.options,b=[],A=false,O=this.ctx,R;var Q=H.findAll(function(c){return(c.label&&!c.hide)}).size();if(Q){if(!B.HtmlText&&this.textEnabled){var T={size:B.fontSize*1.1,color:B.grid.color};var M=B.legend.position,N=B.legend.margin,L=B.legend.labelBoxWidth,Z=B.legend.labelBoxHeight,S=B.legend.labelBoxMargin,W=I.left+N,U=I.top+N;var a=0;for(R=H.length-1;R>-1;--R){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);a=Math.max(a,O.measureText(E,T))}var K=Math.round(L+S*3+a),C=Math.round(Q*(S+Z)+S);if(M.charAt(0)==\"s\"){U=I.top+this.plotHeight-(N+C)}if(M.charAt(1)==\"e\"){W=I.left+this.plotWidth-(N+K)}var P=Flotr.parseColor(B.legend.backgroundColor||\"rgb(240,240,240)\").scale(null,null,null,B.legend.backgroundOpacity||0.1).toString();O.fillStyle=P;O.fillRect(W,U,K,C);O.strokeStyle=B.legend.labelBoxBorderColor;O.strokeRect(Flotr.toPixel(W),Flotr.toPixel(U),K,C);var G=W+S;var F=U+S;for(R=0;R<H.length;R++){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);O.fillStyle=H[R].color;O.fillRect(G,F,L-1,Z-1);O.strokeStyle=B.legend.labelBoxBorderColor;O.lineWidth=1;O.strokeRect(Math.ceil(G)-1.5,Math.ceil(F)-1.5,L+2,Z+2);O.drawText(E,G+L+S,F+(Z+T.size-O.fontDescent(T))/2,T);F+=Z+S}}else{for(R=0;R<H.length;++R){if(!H[R].label||H[R].hide){continue}if(R%B.legend.noColumns==0){b.push(A?\"</tr><tr>\":\"<tr>\");A=true}var E=B.legend.labelFormatter(H[R].label);b.push('<td class=\"flotr-legend-color-box\"><div style=\"border:1px solid '+B.legend.labelBoxBorderColor+';padding:1px\"><div style=\"width:'+B.legend.labelBoxWidth+\"px;height:\"+B.legend.labelBoxHeight+\"px;background-color:\"+H[R].color+'\"></div></div></td><td class=\"flotr-legend-label\">'+E+\"</td>\")}if(A){b.push(\"</tr>\")}if(b.length>0){var V='<table style=\"font-size:smaller;color:'+B.grid.color+'\">'+b.join(\"\")+\"</table>\";if(B.legend.container!=null){$(B.legend.container).update(V)}else{var D=\"\";var M=B.legend.position,N=B.legend.margin;if(M.charAt(0)==\"n\"){D+=\"top:\"+(N+I.top)+\"px;\"}else{if(M.charAt(0)==\"s\"){D+=\"bottom:\"+(N+I.bottom)+\"px;\"}}if(M.charAt(1)==\"e\"){D+=\"right:\"+(N+I.right)+\"px;\"}else{if(M.charAt(1)==\"w\"){D+=\"left:\"+(N+I.left)+\"px;\"}}var J=this.el.insert('<div class=\"flotr-legend\" style=\"position:absolute;z-index:2;'+D+'\">'+V+\"</div>\").select(\"div.flotr-legend\").first();if(B.legend.backgroundOpacity!=0){var Y=B.legend.backgroundColor;if(Y==null){var X=(B.grid.backgroundColor!=null)?B.grid.backgroundColor:Flotr.extractColor(J);Y=Flotr.parseColor(X).adjust(null,null,null,1).toString()}this.el.insert('<div class=\"flotr-legend-bg\" style=\"position:absolute;width:'+J.getWidth()+\"px;height:\"+J.getHeight()+\"px;\"+D+\"background-color:\"+Y+';\"> </div>').select(\"div.flotr-legend-bg\").first().setStyle({opacity:B.legend.backgroundOpacity})}}}}}},getEventPosition:function(C){var G=this.overlay.cumulativeOffset(),F=(C.pageX-G.left-this.plotOffset.left),E=(C.pageY-G.top-this.plotOffset.top),D=0,B=0;if(C.pageX==null&&C.clientX!=null){var H=document.documentElement,A=document.body;D=C.clientX+(H&&H.scrollLeft||A.scrollLeft||0);B=C.clientY+(H&&H.scrollTop||A.scrollTop||0)}else{D=C.pageX;B=C.pageY}return{x:this.axes.x.min+F/this.axes.x.scale,x2:this.axes.x2.min+F/this.axes.x2.scale,y:this.axes.y.max-E/this.axes.y.scale,y2:this.axes.y2.max-E/this.axes.y2.scale,relX:F,relY:E,absX:D,absY:B}},clickHandler:function(A){if(this.ignoreClick){this.ignoreClick=false;return }this.el.fire(\"flotr:click\",[this.getEventPosition(A),this])},mouseMoveHandler:function(A){var B=this.getEventPosition(A);this.lastMousePos.pageX=B.absX;this.lastMousePos.pageY=B.absY;if(this.selectionInterval==null&&(this.options.mouse.track||this.series.any(function(C){return C.mouse&&C.mouse.track}))){this.hit(B)}this.el.fire(\"flotr:mousemove\",[A,B,this])},mouseDownHandler:function(C){if(C.isRightClick()){C.stop();var B=this.overlay;B.hide();function A(){B.show();$(document).stopObserving(\"mousemove\",A)}$(document).observe(\"mousemove\",A);return }if(!this.options.selection.mode||!C.isLeftClick()){return }this.setSelectionPos(this.selection.first,C);if(this.selectionInterval!=null){clearInterval(this.selectionInterval)}this.lastMousePos.pageX=null;this.selectionInterval=setInterval(this.updateSelection.bind(this),1000/this.options.selection.fps);this.mouseUpHandler=this.mouseUpHandler.bind(this);$(document).observe(\"mouseup\",this.mouseUpHandler)},fireSelectEvent:function(){var A=this.axes,F=this.selection,C=(F.first.x<=F.second.x)?F.first.x:F.second.x,B=(F.first.x<=F.second.x)?F.second.x:F.first.x,E=(F.first.y>=F.second.y)?F.first.y:F.second.y,D=(F.first.y>=F.second.y)?F.second.y:F.first.y;C=A.x.min+C/A.x.scale;B=A.x.min+B/A.x.scale;E=A.y.max-E/A.y.scale;D=A.y.max-D/A.y.scale;this.el.fire(\"flotr:select\",[{x1:C,y1:E,x2:B,y2:D},this])},mouseUpHandler:function(A){$(document).stopObserving(\"mouseup\",this.mouseUpHandler);A.stop();if(this.selectionInterval!=null){clearInterval(this.selectionInterval);this.selectionInterval=null}this.setSelectionPos(this.selection.second,A);this.clearSelection();if(this.selectionIsSane()){this.drawSelection();this.fireSelectEvent();this.ignoreClick=true}},setSelectionPos:function(D,B){var A=this.options,C=$(this.overlay).cumulativeOffset();if(A.selection.mode.indexOf(\"x\")==-1){D.x=(D==this.selection.first)?0:this.plotWidth}else{D.x=B.pageX-C.left-this.plotOffset.left;D.x=Math.min(Math.max(0,D.x),this.plotWidth)}if(A.selection.mode.indexOf(\"y\")==-1){D.y=(D==this.selection.first)?0:this.plotHeight}else{D.y=B.pageY-C.top-this.plotOffset.top;D.y=Math.min(Math.max(0,D.y),this.plotHeight)}},updateSelection:function(){if(this.lastMousePos.pageX==null){return }this.setSelectionPos(this.selection.second,this.lastMousePos);this.clearSelection();if(this.selectionIsSane()){this.drawSelection()}},clearSelection:function(){if(this.prevSelection==null){return }var G=this.prevSelection,E=this.octx,C=this.plotOffset,A=Math.min(G.first.x,G.second.x),F=Math.min(G.first.y,G.second.y),B=Math.abs(G.second.x-G.first.x),D=Math.abs(G.second.y-G.first.y);E.clearRect(A+C.left-E.lineWidth,F+C.top-E.lineWidth,B+E.lineWidth*2,D+E.lineWidth*2);this.prevSelection=null},setSelection:function(G){var B=this.options,H=this.axes.x,A=this.axes.y,F=yaxis.scale,D=xaxis.scale,E=B.selection.mode.indexOf(\"x\")!=-1,C=B.selection.mode.indexOf(\"y\")!=-1;this.clearSelection();this.selection.first.y=E?0:(A.max-G.y1)*F;this.selection.second.y=E?this.plotHeight:(A.max-G.y2)*F;this.selection.first.x=C?0:(G.x1-H.min)*D;this.selection.second.x=C?this.plotWidth:(G.x2-H.min)*D;this.drawSelection();this.fireSelectEvent()},drawSelection:function(){var C=this.prevSelection,F=this.selection,H=this.octx,I=this.options,A=this.plotOffset;if(C!=null&&F.first.x==C.first.x&&F.first.y==C.first.y&&F.second.x==C.second.x&&F.second.y==C.second.y){return }H.strokeStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.8).toString();H.lineWidth=1;H.lineJoin=\"round\";H.fillStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.4).toString();this.prevSelection={first:{x:F.first.x,y:F.first.y},second:{x:F.second.x,y:F.second.y}};var E=Math.min(F.first.x,F.second.x),D=Math.min(F.first.y,F.second.y),G=Math.abs(F.second.x-F.first.x),B=Math.abs(F.second.y-F.first.y);H.fillRect(E+A.left,D+A.top,G,B);H.strokeRect(E+A.left,D+A.top,G,B)},selectionIsSane:function(){var A=this.selection;return Math.abs(A.second.x-A.first.x)>=5&&Math.abs(A.second.y-A.first.y)>=5},clearHit:function(){if(this.prevHit){var B=this.options,A=this.plotOffset,C=this.prevHit;this.octx.clearRect(this.tHoz(C.x)+A.left-B.points.radius*2,this.tVert(C.y)+A.top-B.points.radius*2,B.points.radius*3+B.points.lineWidth*3,B.points.radius*3+B.points.lineWidth*3);this.prevHit=null}},hit:function(I){var G=this.series,C=this.options,R=this.prevHit,H=this.plotOffset,D=this.octx,S,A,M,Q,L={dist:Number.MAX_VALUE,x:null,y:null,relX:I.relX,relY:I.relY,absX:I.absX,absY:I.absY,mouse:null};for(Q=0;Q<G.length;Q++){s=G[Q];if(!s.mouse.track){continue}S=s.data;A=(s.xaxis.scale*s.mouse.sensibility);M=(s.yaxis.scale*s.mouse.sensibility);for(var P=0,B,E;P<S.length;P++){if(S[P][1]===null){continue}B=Math.pow(s.xaxis.scale*(S[P][0]-I.x),2);E=Math.pow(s.yaxis.scale*(S[P][1]-I.y),2);if(B<A&&E<M&&Math.sqrt(B+E)<L.dist){L.dist=Math.sqrt(B+E);L.x=S[P][0];L.y=S[P][1];L.mouse=s.mouse}}}if(L.mouse&&L.mouse.track&&!R||(R&&(L.x!=R.x||L.y!=R.y))){var K=this.mouseTrack||this.el.select(\".flotr-mouse-value\")[0],F=\"\",J=C.mouse.position,N=C.mouse.margin,O=\"opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;\";if(!C.mouse.relative){if(J.charAt(0)==\"n\"){F+=\"top:\"+(N+H.top)+\"px;\"}else{if(J.charAt(0)==\"s\"){F+=\"bottom:\"+(N+H.bottom)+\"px;\"}}if(J.charAt(1)==\"e\"){F+=\"right:\"+(N+H.right)+\"px;\"}else{if(J.charAt(1)==\"w\"){F+=\"left:\"+(N+H.left)+\"px;\"}}}else{if(J.charAt(0)==\"n\"){F+=\"bottom:\"+(N-H.top-this.tVert(L.y)+this.canvasHeight)+\"px;\"}else{if(J.charAt(0)==\"s\"){F+=\"top:\"+(N+H.top+this.tVert(L.y))+\"px;\"}}if(J.charAt(1)==\"e\"){F+=\"left:\"+(N+H.left+this.tHoz(L.x))+\"px;\"}else{if(J.charAt(1)==\"w\"){F+=\"right:\"+(N-H.left-this.tHoz(L.x)+this.canvasWidth)+\"px;\"}}}O+=F;if(!K){this.el.insert('<div class=\"flotr-mouse-value\" style=\"'+O+'\"></div>');K=this.mouseTrack=this.el.select(\".flotr-mouse-value\").first()}else{this.mouseTrack=K.setStyle(O)}if(L.x!==null&&L.y!==null){K.show();this.clearHit();if(L.mouse.lineColor!=null){D.save();D.translate(H.left,H.top);D.lineWidth=C.points.lineWidth;D.strokeStyle=L.mouse.lineColor;D.fillStyle=\"#ffffff\";D.beginPath();D.arc(this.tHoz(L.x),this.tVert(L.y),C.mouse.radius,0,2*Math.PI,true);D.fill();D.stroke();D.restore()}this.prevHit=L;var T=L.mouse.trackDecimals;if(T==null||T<0){T=0}K.innerHTML=L.mouse.trackFormatter({x:L.x.toFixed(T),y:L.y.toFixed(T)});K.fire(\"flotr:hit\",[L,this])}else{if(R){K.hide();this.clearHit()}}}},saveImage:function(D,C,A,B){var E=null;switch(D){case\"jpeg\":case\"jpg\":E=Canvas2Image.saveAsJPEG(this.canvas,B,C,A);break;default:case\"png\":E=Canvas2Image.saveAsPNG(this.canvas,B,C,A);break;case\"bmp\":E=Canvas2Image.saveAsBMP(this.canvas,B,C,A);break}if(Object.isElement(E)&&B){this.restoreCanvas();this.canvas.hide();this.overlay.hide();this.el.insert(E.setStyle({position:\"absolute\"}))}},restoreCanvas:function(){this.canvas.show();this.overlay.show();this.el.select(\"img\").invoke(\"remove\")}});Flotr.Color=Class.create({initialize:function(E,D,B,C){this.rgba=[\"r\",\"g\",\"b\",\"a\"];var A=4;while(-1<--A){this[this.rgba[A]]=arguments[A]||((A==3)?1:0)}this.normalize()},adjust:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]+=arguments[A]}}return this.normalize()},clone:function(){return new Flotr.Color(this.r,this.b,this.g,this.a)},limit:function(B,A,C){return Math.max(Math.min(B,C),A)},normalize:function(){var A=this.limit;this.r=A(parseInt(this.r),0,255);this.g=A(parseInt(this.g),0,255);this.b=A(parseInt(this.b),0,255);this.a=A(this.a,0,1);return this},scale:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]*=arguments[A]}}return this.normalize()},distance:function(B){if(!B){return }B=new Flotr.parseColor(B);var C=0;var A=3;while(-1<--A){C+=Math.abs(this[this.rgba[A]]-B[this.rgba[A]])}return C},toString:function(){return(this.a>=1)?\"rgb(\"+[this.r,this.g,this.b].join(\",\")+\")\":\"rgba(\"+[this.r,this.g,this.b,this.a].join(\",\")+\")\"}});Flotr.Color.lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};Flotr.Date={format:function(F,E){if(!F){return }var A=function(H){H=H.toString();return H.length==1?\"0\"+H:H};var D=[];var C=false;for(var B=0;B<E.length;++B){var G=E.charAt(B);if(C){switch(G){case\"h\":G=F.getUTCHours().toString();break;case\"H\":G=A(F.getUTCHours());break;case\"M\":G=A(F.getUTCMinutes());break;case\"S\":G=A(F.getUTCSeconds());break;case\"d\":G=F.getUTCDate().toString();break;case\"m\":G=(F.getUTCMonth()+1).toString();break;case\"y\":G=F.getUTCFullYear().toString();break;case\"b\":G=Flotr.Date.monthNames[F.getUTCMonth()];break}D.push(G);C=false}else{if(G==\"%\"){C=true}else{D.push(G)}}}return D.join(\"\")},timeUnits:{second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000},spec:[[1,\"second\"],[2,\"second\"],[5,\"second\"],[10,\"second\"],[30,\"second\"],[1,\"minute\"],[2,\"minute\"],[5,\"minute\"],[10,\"minute\"],[30,\"minute\"],[1,\"hour\"],[2,\"hour\"],[4,\"hour\"],[8,\"hour\"],[12,\"hour\"],[1,\"day\"],[2,\"day\"],[3,\"day\"],[0.25,\"month\"],[0.5,\"month\"],[1,\"month\"],[2,\"month\"],[3,\"month\"],[6,\"month\"],[1,\"year\"]],monthNames:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"]};"
  },
  {
    "path": "input-scripts/flotr/flotr.debug-0.2.0-alpha.js",
    "content": "//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.\n/* $Id: flotr.js 82 2009-01-12 19:19:31Z fabien.menager $ */\r\n\r\nvar Flotr = {\r\n\tversion: '0.2.0-alpha',\r\n\tauthor: 'Bas Wenneker',\r\n\twebsite: 'http://www.solutoire.com',\r\n\t/**\r\n\t * An object of the default registered graph types. Use Flotr.register(type, functionName)\r\n\t * to add your own type.\r\n\t */\r\n\t_registeredTypes:{\r\n\t\t'lines': 'drawSeriesLines',\r\n\t\t'points': 'drawSeriesPoints',\r\n\t\t'bars': 'drawSeriesBars',\r\n\t\t'candles': 'drawSeriesCandles',\r\n\t\t'pie': 'drawSeriesPie'\r\n\t},\r\n\t/**\r\n\t * Can be used to register your own chart type. Default types are 'lines', 'points' and 'bars'.\r\n\t * This is still experimental.\r\n\t * @todo Test and confirm.\r\n\t * @param {String} type - type of chart, like 'pies', 'bars' etc.\r\n\t * @param {String} functionName - Name of the draw function, like 'drawSeriesPies', 'drawSeriesBars' etc.\r\n\t */\r\n\tregister: function(type, functionName){\r\n\t\tFlotr._registeredTypes[type] = functionName+'';\t\r\n\t},\r\n\t/**\r\n\t * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.\r\n\t * You could also draw graphs by directly calling Flotr.Graph(element, data, options).\r\n\t * @param {Element} el - element to insert the graph into\r\n\t * @param {Object} data - an array or object of dataseries\r\n\t * @param {Object} options - an object containing options\r\n\t * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph\r\n\t * @return {Class} returns a new graph object and of course draws the graph.\r\n\t */\r\n\tdraw: function(el, data, options, _GraphKlass_){\t\r\n\t\t_GraphKlass_ = _GraphKlass_ || Flotr.Graph;\r\n\t\treturn new _GraphKlass_(el, data, options);\r\n\t},\r\n\t/**\r\n\t * Collects dataseries from input and parses the series into the right format. It returns an Array \r\n\t * of Objects each having at least the 'data' key set.\r\n\t * @param {Array/Object} data - Object or array of dataseries\r\n\t * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)})\r\n\t */\r\n\tgetSeries: function(data){\r\n\t\treturn data.collect(function(serie){\r\n\t\t\tvar i, serie = (serie.data) ? Object.clone(serie) : {'data': serie};\r\n\t\t\tfor (i = serie.data.length-1; i > -1; --i) {\r\n\t\t\t\tserie.data[i][1] = (serie.data[i][1] === null ? null : parseFloat(serie.data[i][1])); \r\n\t\t\t}\r\n\t\t\treturn serie;\r\n\t\t});\r\n\t},\r\n\t/**\r\n\t * Recursively merges two objects.\r\n\t * @param {Object} src - source object (likely the object with the least properties)\r\n\t * @param {Object} dest - destination object (optional, object with the most properties)\r\n\t * @return {Object} recursively merged Object\r\n\t */\r\n\tmerge: function(src, dest){\r\n\t\tvar result = dest || {};\r\n\t\tfor(var i in src){\r\n\t\t\tresult[i] = (src[i] != null && typeof(src[i]) == 'object' && !(src[i].constructor == Array || src[i].constructor == RegExp) && !Object.isElement(src[i])) ? Flotr.merge(src[i], dest[i]) : result[i] = src[i];\t\t\r\n\t\t}\r\n\t\treturn result;\r\n\t},\t\r\n\t/**\r\n\t * Function calculates the ticksize and returns it.\r\n\t * @param {Integer} noTicks - number of ticks\r\n\t * @param {Integer} min - lower bound integer value for the current axis\r\n\t * @param {Integer} max - upper bound integer value for the current axis\r\n\t * @param {Integer} decimals - number of decimals for the ticks\r\n\t * @return {Integer} returns the ticksize in pixels\r\n\t */\r\n\tgetTickSize: function(noTicks, min, max, decimals){\r\n\t\tvar delta = (max - min) / noTicks;\t\r\n\t\tvar magn = Flotr.getMagnitude(delta);\r\n\t\t\r\n\t\t// Norm is between 1.0 and 10.0.\r\n\t\tvar norm = delta / magn;\r\n\t\t\r\n\t\tvar tickSize = 10;\r\n\t\tif(norm < 1.5) tickSize = 1;\r\n\t\telse if(norm < 2.25) tickSize = 2;\r\n\t\telse if(norm < 3) tickSize = ((decimals == 0) ? 2 : 2.5);\r\n\t\telse if(norm < 7.5) tickSize = 5;\r\n\t\t\r\n\t\treturn tickSize * magn;\r\n\t},\r\n\t/**\r\n\t * Default tick formatter.\r\n\t * @param {String/Integer} val - tick value integer\r\n\t * @return {String} formatted tick string\r\n\t */\r\n\tdefaultTickFormatter: function(val){\r\n\t\treturn val+'';\r\n\t},\r\n\t/**\r\n\t * Formats the mouse tracker values.\r\n\t * @param {Object} obj - Track value Object {x:..,y:..}\r\n\t * @return {String} Formatted track string\r\n\t */\r\n\tdefaultTrackFormatter: function(obj){\r\n\t\treturn '('+obj.x+', '+obj.y+')';\r\n\t}, \r\n\tdefaultPieLabelFormatter: function(slice) {\r\n\t  return (slice.fraction*100).toFixed(2)+'%';\r\n\t},\r\n\t/**\r\n\t * Returns the magnitude of the input value.\r\n\t * @param {Integer/Float} x - integer or float value\r\n\t * @return {Integer/Float} returns the magnitude of the input value\r\n\t */\r\n\tgetMagnitude: function(x){\r\n\t\treturn Math.pow(10, Math.floor(Math.log(x) / Math.LN10));\r\n\t},\r\n\ttoPixel: function(val){\r\n\t\treturn Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);\r\n\t},\r\n\ttoRad: function(angle){\r\n\t\treturn -angle * (Math.PI/180);\r\n\t},\r\n\t/**\r\n\t * Parses a color string and returns a corresponding Color.\r\n\t * @param {String} str - string thats representing a color\r\n\t * @return {Color} returns a Color object or false\r\n\t */\r\n\tparseColor: function(str){\r\n\t\tif (str instanceof Flotr.Color) return str;\r\n\t\t\r\n\t\tvar result, Color = Flotr.Color;\r\n\r\n\t\t// rgb(num,num,num)\r\n\t\tif((result = /rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(str)))\r\n\t\t\treturn new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));\r\n\t\r\n\t\t// rgba(num,num,num,num)\r\n\t\tif((result = /rgba\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(str)))\r\n\t\t\treturn new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));\r\n\t\t\t\r\n\t\t// rgb(num%,num%,num%)\r\n\t\tif((result = /rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(str)))\r\n\t\t\treturn new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);\r\n\t\r\n\t\t// rgba(num%,num%,num%,num)\r\n\t\tif((result = /rgba\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(str)))\r\n\t\t\treturn new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));\r\n\t\t\t\r\n\t\t// #a0b1c2\r\n\t\tif((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))\r\n\t\t\treturn new Color(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16));\r\n\t\r\n\t\t// #fff\r\n\t\tif((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))\r\n\t\t\treturn new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));\r\n\r\n\t\t// Otherwise, we're most likely dealing with a named color.\r\n\t\tvar name = str.strip().toLowerCase();\r\n\t\tif(name == 'transparent'){\r\n\t\t\treturn new Color(255, 255, 255, 0);\r\n\t\t}\r\n\t\treturn ((result = Color.lookupColors[name])) ? new Color(result[0], result[1], result[2]) : false;\r\n\t},\r\n\t/**\r\n\t * Extracts the background-color of the passed element.\r\n\t * @param {Element} element\r\n\t * @return {String} color string\r\n\t */\r\n\textractColor: function(element){\r\n\t\tvar color;\r\n\t\t// Loop until we find an element with a background color and stop when we hit the body element. \r\n\t\tdo {\r\n\t\t\tcolor = element.getStyle('background-color').toLowerCase();\r\n\t\t\tif(!(color == '' || color == 'transparent')) break;\r\n\t\t\telement = element.up(0);\r\n\t\t} while(!element.nodeName.match(/^body$/i));\r\n\r\n\t\t// Catch Safari's way of signaling transparent.\r\n\t\treturn (color == 'rgba(0, 0, 0, 0)') ? 'transparent' : color;\r\n\t}\r\n};\r\n/**\r\n * Flotr Graph class that plots a graph on creation.\r\n\r\n */\r\nFlotr.Graph = Class.create({\r\n\t/**\r\n\t * Flotr Graph constructor.\r\n\t * @param {Element} el - element to insert the graph into\r\n\t * @param {Object} data - an array or object of dataseries\r\n \t * @param {Object} options - an object containing options\r\n\t */\r\n\tinitialize: function(el, data, options){\r\n\t\tthis.el = $(el);\r\n\t\t\r\n\t\tif (!this.el) throw 'The target container doesn\\'t exist';\r\n\t\t\r\n\t\tthis.data = data;\r\n\t\tthis.series = Flotr.getSeries(data);\r\n\t\tthis.setOptions(options);\r\n\t\t\r\n\t\t// Initialize some variables\r\n\t\tthis.lastMousePos = { pageX: null, pageY: null };\r\n\t\tthis.selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} };\r\n\t\tthis.prevSelection = null;\r\n\t\tthis.selectionInterval = null;\r\n\t\tthis.ignoreClick = false;   \r\n\t\tthis.prevHit = null;\r\n    \r\n\t\t// Create and prepare canvas.\r\n\t\tthis.constructCanvas();\r\n\t\t\r\n\t\t// Add event handlers for mouse tracking, clicking and selection\r\n\t\tthis.initEvents();\r\n\t\t\r\n\t\tthis.findDataRanges();\r\n\t\tthis.calculateTicks(this.axes.x);\r\n\t\tthis.calculateTicks(this.axes.x2);\r\n\t\tthis.calculateTicks(this.axes.y);\r\n\t\tthis.calculateTicks(this.axes.y2);\r\n\t\t\r\n\t\tthis.calculateSpacing();\r\n\t\tthis.draw();\r\n\t\tthis.insertLegend();\r\n    \r\n    // Graph and Data tabs\r\n    if (this.options.spreadsheet.show) \r\n      this.constructTabs();\r\n\t},\r\n\t/**\r\n\t * Sets options and initializes some variables and color specific values, used by the constructor. \r\n\t * @param {Object} opts - options object\r\n\t */\r\n  setOptions: function(opts){\r\n    var options = {\r\n      colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.\r\n      title: null,\r\n      subtitle: null,\r\n      legend: {\r\n        show: true,            // => setting to true will show the legend, hide otherwise\r\n        noColumns: 1,          // => number of colums in legend table // @todo: doesn't work for HtmlText = false\r\n        labelFormatter: Prototype.K, // => fn: string -> string\r\n        labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes\r\n        labelBoxWidth: 14,\r\n        labelBoxHeight: 10,\r\n        labelBoxMargin: 5,\r\n        container: null,       // => container (as jQuery object) to put legend in, null means default on top of graph\r\n        position: 'nw',        // => position of default legend container within plot\r\n        margin: 5,             // => distance from grid edge to default legend container within plot\r\n        backgroundColor: null, // => null means auto-detect\r\n        backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background\r\n      },\r\n      xaxis: {\r\n        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]\r\n        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise\r\n        labelsAngle: 0,        // => Labels' angle, in degrees\r\n        title: null,           // => axis title\r\n        titleAngle: 0,         // => axis title's angle, in degrees\r\n        noTicks: 5,            // => number of ticks for automagically generated ticks\r\n        tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string\r\n        tickDecimals: null,    // => no. of decimals, null means auto\r\n        min: null,             // => min. value to show, null means set automatically\r\n        max: null,             // => max. value to show, null means set automatically\r\n        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max\r\n        color: null\r\n      },\r\n      x2axis: {},\r\n      yaxis: {\r\n        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]\r\n        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise\r\n        labelsAngle: 0,        // => Labels' angle, in degrees\r\n        title: null,           // => axis title\r\n        titleAngle: 90,        // => axis title's angle, in degrees\r\n        noTicks: 5,            // => number of ticks for automagically generated ticks\r\n        tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string\r\n        tickDecimals: null,    // => no. of decimals, null means auto\r\n        min: null,             // => min. value to show, null means set automatically\r\n        max: null,             // => max. value to show, null means set automatically\r\n        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max\r\n        color: null\r\n      },\r\n      y2axis: {\r\n      \ttitleAngle: 270\r\n      },\r\n      points: {\r\n        show: false,           // => setting to true will show points, false will hide\r\n        radius: 3,             // => point radius (pixels)\r\n        lineWidth: 2,          // => line width in pixels\r\n        fill: true,            // => true to fill the points with a color, false for (transparent) no fill\r\n        fillColor: '#FFFFFF',  // => fill color\r\n        fillOpacity: 0.4\r\n      },\r\n      lines: {\r\n        show: false,           // => setting to true will show lines, false will hide\r\n        lineWidth: 2,          // => line width in pixels\r\n        fill: false,           // => true to fill the area from the line to the x axis, false for (transparent) no fill\r\n        fillColor: null,       // => fill color\r\n        fillOpacity: 0.4       // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill\r\n      },\r\n      bars: {\r\n        show: false,           // => setting to true will show bars, false will hide\r\n        lineWidth: 2,          // => in pixels\r\n        barWidth: 1,           // => in units of the x axis\r\n        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill\r\n        fillColor: null,       // => fill color\r\n        fillOpacity: 0.4,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill\r\n        horizontal: false,\r\n        stacked: false\r\n      },\r\n      candles: {\r\n        show: false,           // => setting to true will show candle sticks, false will hide\r\n        lineWidth: 1,          // => in pixels\r\n        wickLineWidth: 1,      // => in pixels\r\n        candleWidth: 0.6,      // => in units of the x axis\r\n        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill\r\n        upFillColor: '#00A8F0',// => up sticks fill color\r\n        downFillColor: '#CB4B4B',// => down sticks fill color\r\n        fillOpacity: 0.5,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill\r\n        barcharts: false       // => draw as barcharts (not standard bars but financial barcharts)\r\n      },\r\n      pie: {\r\n        show: false,           // => setting to true will show bars, false will hide\r\n        lineWidth: 1,          // => in pixels\r\n        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill\r\n        fillColor: null,       // => fill color\r\n        fillOpacity: 0.6,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill\r\n        explode: 6,\r\n        sizeRatio: 0.6,\r\n        startAngle: Math.PI/4,\r\n        labelFormatter: Flotr.defaultPieLabelFormatter,\r\n        pie3D: false,\r\n        pie3DviewAngle: (Math.PI/2 * 0.8),\r\n        pie3DspliceThickness: 20\r\n      },\r\n      grid: {\r\n        color: '#545454',      // => primary color used for outline and labels\r\n        backgroundColor: null, // => null for transparent, else color\r\n        tickColor: '#DDDDDD',  // => color used for the ticks\r\n        labelMargin: 3,        // => margin in pixels\r\n        verticalLines: true,   // => whether to show gridlines in vertical direction\r\n        horizontalLines: true, // => whether to show gridlines in horizontal direction\r\n        outlineWidth: 2        // => width of the grid outline/border in pixels\r\n      },\r\n      selection: {\r\n        mode: null,            // => one of null, 'x', 'y' or 'xy'\r\n        color: '#B6D9FF',      // => selection box color\r\n        fps: 20                // => frames-per-second\r\n      },\r\n      mouse: {\r\n        track: false,          // => true to track the mouse, no tracking otherwise\r\n        position: 'se',        // => position of the value box (default south-east)\r\n        relative: false,       // => next to the mouse cursor\r\n        trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box\r\n        margin: 5,             // => margin in pixels of the valuebox\r\n        lineColor: '#FF3F19',  // => line color of points that are drawn when mouse comes near a value of a series\r\n        trackDecimals: 1,      // => decimals for the track values\r\n        sensibility: 2,        // => the lower this number, the more precise you have to aim to show a value\r\n        radius: 3              // => radius of the track point\r\n      },\r\n      shadowSize: 4,           // => size of the 'fake' shadow\r\n      defaultType: 'lines',    // => default series type\r\n      HtmlText: true,          // => wether to draw the text using HTML or on the canvas\r\n      fontSize: 7.5,             // => canvas' text font size\r\n      spreadsheet: {\r\n      \tshow: false,           // => show the data grid using two tabs\r\n      \ttabGraphLabel: 'Graph',\r\n      \ttabDataLabel: 'Data',\r\n      \ttoolbarDownload: 'Download CSV', // @todo: add language support\r\n      \ttoolbarSelectAll: 'Select all'\r\n      }\r\n    }\r\n    \r\n    options.x2axis = Object.extend(Object.clone(options.xaxis), options.x2axis);\r\n    options.y2axis = Object.extend(Object.clone(options.yaxis), options.y2axis);\r\n    this.options = Flotr.merge((opts || {}), options);\r\n    \r\n    this.axes = {\r\n      x:  {options: this.options.xaxis,  n: 1}, \r\n      x2: {options: this.options.x2axis, n: 2}, \r\n      y:  {options: this.options.yaxis,  n: 1}, \r\n      y2: {options: this.options.y2axis, n: 2}\r\n    };\r\n\t\t\r\n\t\t// Initialize some variables used throughout this function.\r\n\t\tvar assignedColors = [],\r\n\t\t    colors = [],\r\n\t\t    ln = this.series.length,\r\n\t\t    neededColors = this.series.length,\r\n\t\t    oc = this.options.colors, \r\n\t\t    usedColors = [],\r\n\t\t    variation = 0,\r\n\t\t    c, i, j, s, tooClose;\r\n\r\n\t\t// Collect user-defined colors from series.\r\n\t\tfor(i = neededColors - 1; i > -1; --i){\r\n\t\t\tc = this.series[i].color;\r\n\t\t\tif(c != null){\r\n\t\t\t\t--neededColors;\r\n\t\t\t\tif(Object.isNumber(c)) assignedColors.push(c);\r\n\t\t\t\telse usedColors.push(Flotr.parseColor(c));\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t// Calculate the number of colors that need to be generated.\r\n\t\tfor(i = assignedColors.length - 1; i > -1; --i)\r\n\t\t\tneededColors = Math.max(neededColors, assignedColors[i] + 1);\r\n\r\n\t\t// Generate needed number of colors.\r\n\t\tfor(i = 0; colors.length < neededColors;){\r\n\t\t\tc = (oc.length == i) ? new Flotr.Color(100, 100, 100) : Flotr.parseColor(oc[i]);\r\n\t\t\t\r\n\t\t\t// Make sure each serie gets a different color.\r\n\t\t\tvar sign = variation % 2 == 1 ? -1 : 1;\r\n\t\t\tvar factor = 1 + sign * Math.ceil(variation / 2) * 0.2;\r\n\t\t\tc.scale(factor, factor, factor);\r\n\r\n\t\t\t/**\r\n\t\t\t * @todo if we're getting too close to something else, we should probably skip this one\r\n\t\t\t */\r\n\t\t\tcolors.push(c);\r\n\t\t\t\r\n\t\t\tif(++i >= oc.length){\r\n\t\t\t\ti = 0;\r\n\t\t\t\t++variation;\r\n\t\t\t}\r\n\t\t}\r\n\t\r\n\t\t// Fill the options with the generated colors.\r\n\t\tfor(i = 0, j = 0; i < ln; ++i){\r\n\t\t\ts = this.series[i];\r\n\r\n\t\t\t// Assign the color.\r\n\t\t\tif(s.color == null){\r\n\t\t\t\ts.color = colors[j++].toString();\r\n\t\t\t}else if(Object.isNumber(s.color)){\r\n\t\t\t\ts.color = colors[s.color].toString();\r\n\t\t\t}\r\n\t\t\t\r\n      if (!s.xaxis) s.xaxis = this.axes.x;\r\n           if (s.xaxis == 1) s.xaxis = this.axes.x;\r\n      else if (s.xaxis == 2) s.xaxis = this.axes.x2;\r\n  \r\n      if (!s.yaxis) s.yaxis = this.axes.y;\r\n           if (s.yaxis == 1) s.yaxis = this.axes.y;\r\n      else if (s.yaxis == 2) s.yaxis = this.axes.y2;\r\n\t\t\t\r\n\t\t\t// Apply missing options to the series.\r\n\t\t\ts.lines   = Object.extend(Object.clone(this.options.lines), s.lines);\r\n\t\t\ts.points  = Object.extend(Object.clone(this.options.points), s.points);\r\n\t\t\ts.bars    = Object.extend(Object.clone(this.options.bars), s.bars);\r\n\t\t\ts.candles = Object.extend(Object.clone(this.options.candles), s.candles);\r\n\t\t\ts.pie     = Object.extend(Object.clone(this.options.pie), s.pie);\r\n\t\t\ts.mouse   = Object.extend(Object.clone(this.options.mouse), s.mouse);\r\n\t\t\t\r\n\t\t\tif(s.shadowSize == null) s.shadowSize = this.options.shadowSize;\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use \r\n\t * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements\r\n\t * are created, the elements are inserted into the container element.\r\n\t */\r\n\tconstructCanvas: function(){\r\n\t\tvar el = this.el,\r\n\t\t\tsize, c, oc;\r\n\t\t\r\n  \tthis.canvas = el.select('.flotr-canvas')[0];\r\n\t\tthis.overlay = el.select('.flotr-overlay')[0];\r\n\t\t\r\n\t\tel.childElements().invoke('remove');\r\n\r\n\t\t// For positioning labels and overlay.\r\n\t\tel.setStyle({position:'relative', cursor:'default'});\r\n\r\n\t\tthis.canvasWidth = el.getWidth();\r\n\t\tthis.canvasHeight = el.getHeight();\r\n\t\tsize = {'width': this.canvasWidth, 'height': this.canvasHeight};\r\n\r\n\t\tif(this.canvasWidth <= 0 || this.canvasHeight <= 0){\r\n\t\t\tthrow 'Invalid dimensions for plot, width = ' + this.canvasWidth + ', height = ' + this.canvasHeight;\r\n\t\t}\r\n\r\n\t\t// Insert main canvas.\r\n\t\tif (!this.canvas) {\r\n\t\t\tc = this.canvas = new Element('canvas', size);\r\n\t\t\tc.className = 'flotr-canvas';\r\n\t\t\tc = c.writeAttribute('style', 'position:absolute;left:0px;top:0px;');\r\n\t\t} else {\r\n\t\t\tc = this.canvas.writeAttribute(size);\r\n\t\t}\r\n\t\tel.insert(c);\r\n\t\t\r\n\t\tif(Prototype.Browser.IE){\r\n\t\t\tc = window.G_vmlCanvasManager.initElement(c);\r\n\t\t}\r\n\t\tthis.ctx = c.getContext('2d');\r\n    \r\n\t\t// Insert overlay canvas for interactive features.\r\n\t\tif (!this.overlay) {\r\n\t\t\toc = this.overlay = new Element('canvas', size);\r\n\t\t\toc.className = 'flotr-overlay';\r\n\t\t\toc = oc.writeAttribute('style', 'position:absolute;left:0px;top:0px;');\r\n\t\t} else {\r\n\t\t\toc = this.overlay.writeAttribute(size);\r\n\t\t}\r\n\t\tel.insert(oc);\r\n\t\t\r\n\t\tif(Prototype.Browser.IE){\r\n\t\t\toc = window.G_vmlCanvasManager.initElement(oc);\r\n\t\t}\r\n\t\tthis.octx = oc.getContext('2d');\r\n\r\n\t\t// Enable text functions\r\n\t\tif (window.CanvasText) {\r\n\t\t  CanvasText.enable(this.ctx);\r\n\t\t  CanvasText.enable(this.octx);\r\n\t\t  this.textEnabled = true;\r\n\t\t}\r\n\t},\r\n  getTextDimensions: function(text, canvasStyle, HtmlStyle, className) {\r\n    if (!text) return {width:0, height:0};\r\n    \r\n    if (!this.options.HtmlText && this.textEnabled) {\r\n      var bounds = this.ctx.getTextBounds(text, canvasStyle);\r\n      return {\r\n        width: bounds.width+2, \r\n        height: bounds.height+6\r\n      };\r\n    }\r\n    else {\r\n      var dummyDiv = this.el.insert('<div style=\"position:absolute;top:-10000px;'+HtmlStyle+'\" class=\"'+className+' flotr-dummy-div\">' + text + '</div>').select(\".flotr-dummy-div\")[0];\r\n      dim = dummyDiv.getDimensions();\r\n      dummyDiv.remove();\r\n      return dim;\r\n    }\r\n  },\r\n\tloadDataGrid: function(){\r\n    if (this.seriesData) return this.seriesData;\r\n\r\n\t\tvar s = this.series;\r\n\t\tvar dg = [];\r\n\r\n    /* The data grid is a 2 dimensions array. There is a row for each X value.\r\n     * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one)\r\n    **/\r\n\t\tfor(i = 0; i < s.length; ++i){\r\n\t\t\ts[i].data.each(function(v) {\r\n\t\t\t\tvar x = v[0],\r\n\t\t\t\t    y = v[1];\r\n\t\t\t\tif (r = dg.find(function(row) {return row[0] == x})) {\r\n\t\t\t\t\tr[i+1] = y;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tvar newRow = [];\r\n\t\t\t\t\tnewRow[0] = x;\r\n\t\t\t\t\tnewRow[i+1] = y\r\n\t\t\t\t\tdg.push(newRow);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n    // The data grid is sorted by x value\r\n\t\tdg = dg.sortBy(function(v) {\r\n\t\t\treturn v[0];\r\n\t\t});\r\n\t\treturn this.seriesData = dg;\r\n\t},\r\n\t\r\n\t// @todo: make a tab manager (Flotr.Tabs)\r\n  showTab: function(tabName, onComplete){\r\n    var elementsClassNames = 'canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle';\r\n    switch(tabName) {\r\n      case 'graph':\r\n        this.datagrid.up().hide();\r\n        this.el.select(elementsClassNames).invoke('show');\r\n        this.tabs.data.removeClassName('selected');\r\n        this.tabs.graph.addClassName('selected');\r\n      break;\r\n      case 'data':\r\n        this.constructDataGrid();\r\n        this.datagrid.up().show();\r\n        this.el.select(elementsClassNames).invoke('hide');\r\n        this.tabs.data.addClassName('selected');\r\n        this.tabs.graph.removeClassName('selected');\r\n      break;\r\n    }\r\n  },\r\n  constructTabs: function(){\r\n    var tabsContainer = new Element('div', {className:'flotr-tabs-group', style:'position:absolute;left:0px;top:'+this.canvasHeight+'px;width:'+this.canvasWidth+'px;'});\r\n    this.el.insert({bottom: tabsContainer});\r\n    this.tabs = {\r\n    \tgraph: new Element('div', {className:'flotr-tab selected', style:'float:left;'}).update(this.options.spreadsheet.tabGraphLabel),\r\n    \tdata: new Element('div', {className:'flotr-tab', style:'float:left;'}).update(this.options.spreadsheet.tabDataLabel)\r\n    }\r\n    \r\n    tabsContainer.insert(this.tabs.graph).insert(this.tabs.data);\r\n    \r\n    this.el.setStyle({height: this.canvasHeight+this.tabs.data.getHeight()+2+'px'});\r\n\r\n    this.tabs.graph.observe('click', (function() {this.showTab('graph')}).bind(this));\r\n    this.tabs.data.observe('click', (function() {this.showTab('data')}).bind(this));\r\n  },\r\n  \r\n  // @todo: make a spreadsheet manager (Flotr.Spreadsheet)\r\n\tconstructDataGrid: function(){\r\n    // If the data grid has already been built, nothing to do here\r\n    if (this.datagrid) return this.datagrid;\r\n    \r\n\t\tvar i, j, \r\n        s = this.series,\r\n        datagrid = this.loadDataGrid();\r\n\r\n\t\tvar t = this.datagrid = new Element('table', {className:'flotr-datagrid', style:'height:100px;'});\r\n\t\tvar colgroup = ['<colgroup><col />'];\r\n\t\t\r\n\t\t// First row : series' labels\r\n\t\tvar html = ['<tr class=\"first-row\">'];\r\n\t\thtml.push('<th>&nbsp;</th>');\r\n\t\tfor (i = 0; i < s.length; ++i) {\r\n\t\t\thtml.push('<th scope=\"col\">'+(s[i].label || String.fromCharCode(65+i))+'</th>');\r\n\t\t\tcolgroup.push('<col />');\r\n\t\t}\r\n\t\thtml.push('</tr>');\r\n\t\t\r\n\t\t// Data rows\r\n\t\tfor (j = 0; j < datagrid.length; ++j) {\r\n\t\t\thtml.push('<tr>');\r\n\t\t\tfor (i = 0; i < s.length+1; ++i) {\r\n        var tag = 'td';\r\n        var content = (datagrid[j][i] != null ? Math.round(datagrid[j][i]*100000)/100000 : '');\r\n        \r\n        if (i == 0) {\r\n          tag = 'th';\r\n          var label;\r\n          if(this.options.xaxis.ticks) {\r\n            var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == datagrid[j][i] });\r\n            if (tick) label = tick[1];\r\n          } \r\n          else {\r\n            label = this.options.xaxis.tickFormatter(content);\r\n          }\r\n          \r\n          if (label) content = label;\r\n        }\r\n\r\n\t\t\t\thtml.push('<'+tag+(tag=='th'?' scope=\"row\"':'')+'>'+content+'</'+tag+'>');\r\n\t\t\t}\r\n\t\t\thtml.push('</tr>');\r\n\t\t}\r\n\t\tcolgroup.push('</colgroup>');\r\n    t.update(colgroup.join('')+html.join(''));\r\n    \r\n    if (!Prototype.Browser.IE) {\r\n      t.select('td').each(function(td) {\r\n      \ttd.observe('mouseover', function(e){\r\n      \t\ttd = e.element();\r\n      \t\tvar siblings = td.previousSiblings();\r\n      \t\t\r\n      \t\tt.select('th[scope=col]')[siblings.length-1].addClassName('hover');\r\n      \t\tt.select('colgroup col')[siblings.length].addClassName('hover');\r\n      \t});\r\n      \t\r\n      \ttd.observe('mouseout', function(){\r\n      \t\tt.select('colgroup col.hover, th.hover').each(function(e){e.removeClassName('hover')});\r\n      \t});\r\n      });\r\n    }\r\n    \r\n\t\tvar toolbar = new Element('div', {className: 'flotr-datagrid-toolbar'}).\r\n\t    insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarDownload).observe('click', this.downloadCSV.bind(this))).\r\n\t    insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarSelectAll).observe('click', this.selectAllData.bind(this)));\r\n\t\t\r\n\t\tvar container = new Element('div', {className:'flotr-datagrid-container', style:'left:0px;top:0px;width:'+this.canvasWidth+'px;height:'+this.canvasHeight+'px;overflow:auto;'});\r\n\t\tcontainer.insert(toolbar);\r\n\t\tt.wrap(container.hide());\r\n\t\t\r\n\t\tthis.el.insert(container);\r\n    return t;\r\n  },\r\n  selectAllData: function(){\r\n    if (this.tabs) {\r\n      var selection, range, doc, win, node = this.constructDataGrid();\r\n  \r\n      this.showTab('data');\r\n      \r\n      // deferred to be able to select the table\r\n      (function () {\r\n        if ((doc = node.ownerDocument) && (win = doc.defaultView) && \r\n          win.getSelection && doc.createRange && \r\n          (selection = window.getSelection()) && \r\n          selection.removeAllRanges) {\r\n           range = doc.createRange();\r\n           range.selectNode(node);\r\n           selection.removeAllRanges();\r\n           selection.addRange(range);\r\n        }\r\n        else if (document.body && document.body.createTextRange && \r\n          (range = document.body.createTextRange())) {\r\n           range.moveToElementText(node);\r\n           range.select();\r\n        }\r\n      }).defer();\r\n      return true;\r\n    }\r\n    else return false;\r\n  },\r\n  downloadCSV: function(){\r\n    var i, csv = '\"x\"',\r\n        series = this.series,\r\n        dg = this.loadDataGrid();\r\n    \r\n    for (i = 0; i < series.length; ++i) {\r\n      csv += '%09\"'+(series[i].label || String.fromCharCode(65+i))+'\"'; // \\t\r\n    }\r\n    csv += \"%0D%0A\"; // \\r\\n\r\n    \r\n    for (i = 0; i < dg.length; ++i) {\r\n      if (this.options.xaxis.ticks) {\r\n        var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == dg[i][0] });\r\n        if (tick) dg[i][0] = tick[1];\r\n      } else {\r\n        dg[i][0] = this.options.xaxis.tickFormatter(dg[i][0]);\r\n      }\r\n      csv += dg[i].join('%09')+\"%0D%0A\"; // \\t and \\r\\n\r\n    }\r\n    if (Prototype.Browser.IE) {\r\n      csv = csv.gsub('%09', '\\t').gsub('%0A', '\\n').gsub('%0D', '\\r');\r\n      window.open().document.write(csv);\r\n    }\r\n    else {\r\n      window.open('data:text/csv,'+csv);\r\n    }\r\n  },\r\n\t/**\r\n\t * Initializes event some handlers.\r\n\t */\r\n\tinitEvents: function () {\r\n  \t//@todo: maybe stopObserving with only flotr functions\r\n  \tthis.overlay.stopObserving();\r\n  \tthis.overlay.observe('mousedown', this.mouseDownHandler.bind(this));\r\n\t\tthis.overlay.observe('mousemove', this.mouseMoveHandler.bind(this));\r\n\t\tthis.overlay.observe('click', this.clickHandler.bind(this));\r\n\t},\r\n\t/**\r\n\t * Function determines the min and max values for the xaxis and yaxis.\r\n\t */\r\n\tfindDataRanges: function(){\r\n\t\tvar s = this.series, \r\n\t\t    a = this.axes;\r\n\t\t\r\n\t\ta.x.datamin = 0;  a.x.datamax  = 0;\r\n\t\ta.x2.datamin = 0; a.x2.datamax = 0;\r\n\t\ta.y.datamin = 0;  a.y.datamax  = 0;\r\n\t\ta.y2.datamin = 0; a.y2.datamax = 0;\r\n\t\t\r\n\t\tif(s.length > 0){\r\n\t\t\tvar i, j, h, x, y, data, xaxis, yaxis;\r\n\t\t\r\n\t\t\t// Get datamin, datamax start values \r\n\t\t\tfor(i = 0; i < s.length; ++i) {\r\n\t\t\t\tdata = s[i].data, \r\n\t\t\t\txaxis = s[i].xaxis, \r\n\t\t\t\tyaxis = s[i].yaxis;\r\n\t\t\t\t\r\n\t\t\t\tif (data.length > 0 && !s[i].hide) {\r\n\t\t\t\t\tif (!xaxis.used) xaxis.datamin = xaxis.datamax = data[0][0];\r\n\t\t\t\t\tif (!yaxis.used) yaxis.datamin = yaxis.datamax = data[0][1];\r\n\t\t\t\t\txaxis.used = true;\r\n\t\t\t\t\tyaxis.used = true;\r\n\r\n\t\t\t\t\tfor(h = data.length - 1; h > -1; --h){\r\n  \t\t\t\t\tx = data[h][0];\r\n  \t\t\t         if(x < xaxis.datamin) xaxis.datamin = x;\r\n   \t\t\t\t\telse if(x > xaxis.datamax) xaxis.datamax = x;\r\n  \t\t\t    \r\n  \t\t\t\t\tfor(j = 1; j < data[h].length; j++){\r\n  \t\t\t\t\t\ty = data[h][j];\r\n  \t\t\t\t         if(y < yaxis.datamin) yaxis.datamin = y;\r\n  \t  \t\t\t\telse if(y > yaxis.datamax) yaxis.datamax = y;\r\n  \t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tthis.findXAxesValues();\r\n\t\t\r\n\t\tthis.calculateRange(a.x);\r\n\t\tthis.extendXRangeIfNeededByBar(a.x);\r\n\t\t\r\n\t\tif (a.x2.used) {\r\n\t\t\tthis.calculateRange(a.x2);\r\n\t\t  this.extendXRangeIfNeededByBar(a.x2);\r\n\t\t}\r\n\t\t\r\n\t\tthis.calculateRange(a.y);\r\n\t\tthis.extendYRangeIfNeededByBar(a.y);\r\n\t\t\r\n\t\tif (a.y2.used) {\r\n  \t\tthis.calculateRange(a.y2);\r\n  \t\tthis.extendYRangeIfNeededByBar(a.y2);\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Calculates the range of an axis to apply autoscaling.\r\n\t */\r\n\tcalculateRange: function(axis){\r\n\t\tvar o = axis.options,\r\n\t\t  min = o.min != null ? o.min : axis.datamin,\r\n\t\t\tmax = o.max != null ? o.max : axis.datamax,\r\n\t\t\tmargin;\r\n\r\n\t\tif(max - min == 0.0){\r\n\t\t\tvar widen = (max == 0.0) ? 1.0 : 0.01;\r\n\t\t\tmin -= widen;\r\n\t\t\tmax += widen;\r\n\t\t}\r\n\t\taxis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);\r\n\r\n\t\t// Autoscaling.\r\n\t\tif(o.min == null){\r\n\t\t\t// Add a margin.\r\n\t\t\tmargin = o.autoscaleMargin;\r\n\t\t\tif(margin != 0){\r\n\t\t\t\tmin -= axis.tickSize * margin;\r\n\t\t\t\t\r\n\t\t\t\t// Make sure we don't go below zero if all values are positive.\r\n\t\t\t\tif(min < 0 && axis.datamin >= 0) min = 0;\r\n\t\t\t\tmin = axis.tickSize * Math.floor(min / axis.tickSize);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif(o.max == null){\r\n\t\t\tmargin = o.autoscaleMargin;\r\n\t\t\tif(margin != 0){\r\n\t\t\t\tmax += axis.tickSize * margin;\r\n\t\t\t\tif(max > 0 && axis.datamax <= 0) max = 0;\t\t\t\t\r\n\t\t\t\tmax = axis.tickSize * Math.ceil(max / axis.tickSize);\r\n\t\t\t}\r\n\t\t}\r\n\t\taxis.min = min;\r\n\t\taxis.max = max;\r\n\t},\r\n\t/**\r\n\t * Bar series autoscaling in x direction.\r\n\t */\r\n\textendXRangeIfNeededByBar: function(axis){\r\n\t\tif(axis.options.max == null){\r\n\t\t\tvar newmax = axis.max,\r\n\t\t\t    i, s, b, c,\r\n\t\t\t    stackedSums = [], \r\n\t\t\t    lastSerie = null;\r\n\r\n\t\t\tfor(i = 0; i < this.series.length; ++i){\r\n\t\t\t\ts = this.series[i];\r\n\t\t\t\tb = s.bars;\r\n\t\t\t\tc = s.candles;\r\n\t\t\t\tif(s.axis == axis && (b.show || c.show)) {\r\n\t\t\t\t\tif (!b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){\r\n\t\t\t\t\t\tnewmax = axis.max + s.bars.barWidth;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(b.stacked && b.horizontal){\r\n\t\t\t\t\t\tfor (j = 0; j < s.data.length; j++) {\r\n\t\t\t\t\t\t\tif (s.bars.show && s.bars.stacked) {\r\n\t\t\t\t\t\t\t\tvar x = s.data[j][0];\r\n\t\t\t\t\t\t\t\tstackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];\r\n\t\t\t\t\t\t\t\tlastSerie = s;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t    \r\n\t\t\t\t\t\tfor (j = 0; j < stackedSums.length; j++) {\r\n\t\t\t\t    \tnewmax = Math.max(stackedSums[j], newmax);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\taxis.lastSerie = lastSerie;\r\n\t\t\taxis.max = newmax;\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Bar series autoscaling in y direction.\r\n\t */\r\n\textendYRangeIfNeededByBar: function(axis){\r\n\t\tif(axis.options.max == null){\r\n\t\t\tvar newmax = axis.max,\r\n\t\t\t\t  i, s, b, c,\r\n\t\t\t\t  stackedSums = [],\r\n\t\t\t\t  lastSerie = null;\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\tfor(i = 0; i < this.series.length; ++i){\r\n\t\t\t\ts = this.series[i];\r\n\t\t\t\tb = s.bars;\r\n\t\t\t\tc = s.candles;\r\n\t\t\t\tif (s.yaxis == axis && b.show && !s.hide) {\r\n\t\t\t\t\tif (b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){\r\n\t\t\t\t\t\tnewmax = axis.max + b.barWidth;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(b.stacked && !b.horizontal){\r\n\t\t\t\t\t\tfor (j = 0; j < s.data.length; j++) {\r\n\t\t\t\t\t\t\tif (s.bars.show && s.bars.stacked) {\r\n\t\t\t\t\t\t\t\tvar x = s.data[j][0];\r\n\t\t\t\t\t\t\t\tstackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];\r\n\t\t\t\t\t\t\t\tlastSerie = s;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tfor (j = 0; j < stackedSums.length; j++) {\r\n\t\t\t\t\t\t\tnewmax = Math.max(stackedSums[j], newmax);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\taxis.lastSerie = lastSerie;\r\n\t\t\taxis.max = newmax;\r\n\t\t}\r\n\t},\r\n\t/** \r\n\t * Find every values of the x axes\r\n\t */\r\n\tfindXAxesValues: function(){\r\n\t\tfor(i = this.series.length-1; i > -1 ; --i){\r\n\t\t\ts = this.series[i];\r\n\t\t\ts.xaxis.values = s.xaxis.values || [];\r\n\t\t\tfor (j = s.data.length-1; j > -1 ; --j){\r\n\t\t\t\ts.xaxis.values[s.data[j][0]] = {};\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Calculate axis ticks.\r\n\t * @param {Object} axis - axis object\r\n\t * @param {Object} o - axis options\r\n\t */\r\n\tcalculateTicks: function(axis){\r\n\t\tvar o = axis.options, i, v;\r\n\t\t\r\n\t\taxis.ticks = [];\t\r\n\t\tif(o.ticks){\r\n\t\t\tvar ticks = o.ticks, t, label;\r\n\r\n\t\t\tif(Object.isFunction(ticks)){\r\n\t\t\t\tticks = ticks({min: axis.min, max: axis.max});\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Clean up the user-supplied ticks, copy them over.\r\n\t\t\tfor(i = 0; i < ticks.length; ++i){\r\n\t\t\t\tt = ticks[i];\r\n\t\t\t\tif(typeof(t) == 'object'){\r\n\t\t\t\t\tv = t[0];\r\n\t\t\t\t\tlabel = (t.length > 1) ? t[1] : o.tickFormatter(v);\r\n\t\t\t\t}else{\r\n\t\t\t\t\tv = t;\r\n\t\t\t\t\tlabel = o.tickFormatter(v);\r\n\t\t\t\t}\r\n\t\t\t\taxis.ticks[i] = { v: v, label: label };\r\n\t\t\t}\r\n\t\t}\r\n    else {\r\n\t\t\t// Round to nearest multiple of tick size.\r\n\t\t\tvar start = axis.tickSize * Math.ceil(axis.min / axis.tickSize),\r\n\t\t\t\t  decimals;\r\n\t\t\t\r\n\t\t\t// Then store all possible ticks.\r\n\t\t\tfor(i = 0; start + i * axis.tickSize <= axis.max; ++i){\r\n\t\t\t\tv = start + i * axis.tickSize;\r\n\t\t\t\t\r\n\t\t\t\t// Round (this is always needed to fix numerical instability).\r\n\t\t\t\tdecimals = o.tickDecimals;\r\n\t\t\t\tif(decimals == null) decimals = 1 - Math.floor(Math.log(axis.tickSize) / Math.LN10);\r\n\t\t\t\tif(decimals < 0) decimals = 0;\r\n\t\t\t\t\r\n\t\t\t\tv = v.toFixed(decimals);\r\n\t\t\t\taxis.ticks.push({ v: v, label: o.tickFormatter(v) });\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Calculates axis label sizes.\r\n\t */\r\n\tcalculateSpacing: function(){\r\n\t\tvar a = this.axes,\r\n  \t\t\toptions = this.options,\r\n  \t\t\tseries = this.series,\r\n  \t\t\tmargin = options.grid.labelMargin,\r\n  \t\t\tx = a.x,\r\n  \t\t\tx2 = a.x2,\r\n  \t\t\ty = a.y,\r\n  \t\t\ty2 = a.y2,\r\n  \t\t\tmaxOutset = 2,\r\n  \t\t\ti, j, l, dim;\r\n\t\t\r\n\t\t// Labels width and height\r\n\t\t[x, x2, y, y2].each(function(axis) {\r\n\t\t\tvar maxLabel = '';\r\n\t\t\t\r\n\t\t  if (axis.options.showLabels) {\r\n\t\t\t\tfor(i = 0; i < axis.ticks.length; ++i){\r\n\t\t\t\t\tl = axis.ticks[i].label.length;\r\n\t\t\t\t\tif(l > maxLabel.length){\r\n\t\t\t\t\t\tmaxLabel = axis.ticks[i].label;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t    }\r\n\t\t  axis.maxLabel  = this.getTextDimensions(maxLabel, {size:options.fontSize, angle: Flotr.toRad(axis.options.labelsAngle)}, 'font-size:smaller;', 'flotr-grid-label');\r\n\t\t  axis.titleSize = this.getTextDimensions(axis.options.title, {size: options.fontSize*1.2, angle: Flotr.toRad(axis.options.titleAngle)}, 'font-weight:bold;', 'flotr-axis-title');\r\n\t\t}, this);\r\n\r\n    // Title height\r\n    dim = this.getTextDimensions(options.title, {size: options.fontSize*1.5}, 'font-size:1em;font-weight:bold;', 'flotr-title');\r\n    this.titleHeight = dim.height;\r\n    \r\n    // Subtitle height\r\n    dim = this.getTextDimensions(options.subtitle, {size: options.fontSize}, 'font-size:smaller;', 'flotr-subtitle');\r\n    this.subtitleHeight = dim.height;\r\n\r\n\t\t// Grid outline line width.\r\n\t\tif(options.show){\r\n\t\t\tmaxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2);\r\n\t\t}\r\n\t\tfor(j = 0; j < options.length; ++j){\r\n\t\t\tif (series[j].points.show){\r\n\t\t\t\tmaxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tvar p = this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};\r\n\t\tp.left = p.right = p.top = p.bottom = maxOutset;\r\n\t\t\r\n\t\tp.bottom += (x.options.showLabels ?  (x.maxLabel.height  + margin) : 0) + \r\n\t\t            (x.options.title ?       (x.titleSize.height + margin) : 0);\r\n\t\t\r\n    p.top    += (x2.options.showLabels ? (x2.maxLabel.height  + margin) : 0) + \r\n                (x2.options.title ?      (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight;\r\n    \r\n\t\tp.left   += (y.options.showLabels ?  (y.maxLabel.width  + margin) : 0) + \r\n                (y.options.title ?       (y.titleSize.width + margin) : 0);\r\n\t\t\r\n\t\tp.right  += (y2.options.showLabels ? (y2.maxLabel.width  + margin) : 0) + \r\n                (y2.options.title ?      (y2.titleSize.width + margin) : 0);\r\n    \r\n    p.top = Math.floor(p.top); // In order the outline not to be blured\r\n    \r\n\t\tthis.plotWidth  = this.canvasWidth - p.left - p.right;\r\n\t\tthis.plotHeight = this.canvasHeight - p.bottom - p.top;\r\n\t\t\r\n\t\tx.scale  = this.plotWidth / (x.max - x.min);\r\n\t\tx2.scale = this.plotWidth / (x2.max - x2.min);\r\n\t\ty.scale  = this.plotHeight / (y.max - y.min);\r\n\t\ty2.scale = this.plotHeight / (y2.max - y2.min);\r\n\t},\r\n\t/**\r\n\t * Draws grid, labels and series.\r\n\t */\r\n\tdraw: function() {\r\n\t\tthis.drawGrid();\r\n\t\tthis.drawLabels();\r\n    this.drawTitles();\r\n    \r\n\t\tif(this.series.length){\r\n\t\t\tthis.el.fire('flotr:beforedraw', [this.series, this]);\r\n\t\t\tfor(var i = 0; i < this.series.length; i++){\r\n\t\t\t\tif (!this.series[i].hide)\r\n\t\t\t\t\tthis.drawSeries(this.series[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.el.fire('flotr:afterdraw', [this.series, this]);\r\n\t},\r\n\t/**\r\n\t * Translates absolute horizontal x coordinates to relative coordinates.\r\n\t * @param {Integer} x - absolute integer x coordinate\r\n\t * @return {Integer} translated relative x coordinate\r\n\t */\r\n\ttHoz: function(x, axis){\r\n\t\taxis = axis || this.axes.x;\r\n\t\treturn (x - axis.min) * axis.scale;\r\n\t},\r\n\t/**\r\n\t * Translates absolute vertical x coordinates to relative coordinates.\r\n\t * @param {Integer} y - absolute integer y coordinate\r\n\t * @return {Integer} translated relative y coordinate\r\n\t */\r\n\ttVert: function(y, axis){\r\n\t\taxis = axis || this.axes.y;\r\n\t\treturn this.plotHeight - (y - axis.min) * axis.scale;\r\n\t},\r\n\t/**\r\n\t * Draws a grid for the graph.\r\n\t */\r\n\tdrawGrid: function(){\r\n\t\tvar v, o = this.options,\r\n\t\t    ctx = this.ctx;\r\n\t\tif(o.grid.verticalLines || o.grid.horizontalLines){\r\n\t\t\tthis.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);\r\n\t\t}\r\n\t\tctx.save();\r\n\t\tctx.translate(this.plotOffset.left, this.plotOffset.top);\r\n\r\n\t\t// Draw grid background, if present in options.\r\n\t\tif(o.grid.backgroundColor != null){\r\n\t\t\tctx.fillStyle = o.grid.backgroundColor;\r\n\t\t\tctx.fillRect(0, 0, this.plotWidth, this.plotHeight);\r\n\t\t}\r\n\t\t\r\n\t\t// Draw grid lines in vertical direction.\r\n\t\tctx.lineWidth = 1;\r\n\t\tctx.strokeStyle = o.grid.tickColor;\r\n\t\tctx.beginPath();\r\n\t\tif(o.grid.verticalLines){\r\n\t\t\tfor(var i = 0; i < this.axes.x.ticks.length; ++i){\r\n\t\t\t\tv = this.axes.x.ticks[i].v;\r\n\t\t\t\t// Don't show lines on upper and lower bounds.\r\n\t\t\t\tif ((v == this.axes.x.min || v == this.axes.x.max) && o.grid.outlineWidth != 0)\r\n\t\t\t\t\tcontinue;\r\n\t\r\n\t\t\t\tctx.moveTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, 0);\r\n\t\t\t\tctx.lineTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, this.plotHeight);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t// Draw grid lines in horizontal direction.\r\n\t\tif(o.grid.horizontalLines){\r\n\t\t\tfor(var j = 0; j < this.axes.y.ticks.length; ++j){\r\n\t\t\t\tv = this.axes.y.ticks[j].v;\r\n\t\t\t\t// Don't show lines on upper and lower bounds.\r\n\t\t\t\tif ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)\r\n\t\t\t\t\tcontinue;\r\n\t\r\n\t\t\t\tctx.moveTo(0, Math.floor(this.tVert(v)) + ctx.lineWidth/2);\r\n\t\t\t\tctx.lineTo(this.plotWidth, Math.floor(this.tVert(v)) + ctx.lineWidth/2);\r\n\t\t\t}\r\n\t\t}\r\n\t\tctx.stroke();\r\n\t\t\r\n\t\t// Draw axis/grid border.\r\n\t\tif(o.grid.outlineWidth != 0) {\r\n\t\t\tctx.lineWidth = o.grid.outlineWidth;\r\n\t\t\tctx.strokeStyle = o.grid.color;\r\n\t\t\tctx.lineJoin = 'round';\r\n\t\t\tctx.strokeRect(0, 0, this.plotWidth, this.plotHeight);\r\n\t\t}\r\n\t\tctx.restore();\r\n\t\tif(o.grid.verticalLines || o.grid.horizontalLines){\r\n\t\t\tthis.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Draws labels for x and y axis.\r\n\t */   \r\n\tdrawLabels: function(){\t\t\r\n\t\t// Construct fixed width label boxes, which can be styled easily. \r\n\t\tvar noLabels = 0, axis,\r\n\t\t\txBoxWidth, i, html, tick,\r\n\t\t\toptions = this.options,\r\n      ctx = this.ctx,\r\n      a = this.axes;\r\n\t\t\r\n\t\tfor(i = 0; i < a.x.ticks.length; ++i){\r\n\t\t\tif (a.x.ticks[i].label) {\r\n\t\t\t\t++noLabels;\r\n\t\t\t}\r\n\t\t}\r\n\t\txBoxWidth = this.plotWidth / noLabels;\r\n    \r\n\t\tif (!options.HtmlText && this.textEnabled) {\r\n\t\t  var style = {\r\n\t\t    size: options.fontSize,\r\n        adjustAlign: true\r\n\t\t  };\r\n\r\n\t\t  // Add x labels.\r\n\t\t  axis = a.x;\r\n\t\t  style.color = axis.options.color || options.grid.color;\r\n\t\t  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){\r\n\t\t    tick = axis.ticks[i];\r\n\t\t    if(!tick.label || tick.label.length == 0) continue;\r\n        \r\n        style.angle = Flotr.toRad(axis.options.labelsAngle);\r\n        style.halign = 'c';\r\n        style.valign = 't';\r\n        \r\n\t\t    ctx.drawText(\r\n\t\t      tick.label,\r\n\t\t      this.plotOffset.left + this.tHoz(tick.v, axis), \r\n\t\t      this.plotOffset.top + this.plotHeight + options.grid.labelMargin,\r\n\t\t      style\r\n\t\t    );\r\n\t\t  }\r\n\t\t  \r\n\t\t  // Add x2 labels.\r\n\t\t  axis = a.x2;\r\n\t\t  style.color = axis.options.color || options.grid.color;\r\n\t\t  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){\r\n\t\t    tick = axis.ticks[i];\r\n\t\t    if(!tick.label || tick.label.length == 0) continue;\r\n        \r\n        style.angle = Flotr.toRad(axis.options.labelsAngle);\r\n        style.halign = 'c';\r\n        style.valign = 'b';\r\n        \r\n\t\t    ctx.drawText(\r\n\t\t      tick.label,\r\n\t\t      this.plotOffset.left + this.tHoz(tick.v, axis), \r\n\t\t      this.plotOffset.top + options.grid.labelMargin,\r\n\t\t      style\r\n\t\t    );\r\n\t\t  }\r\n\t\t  \r\n\t\t  // Add y labels.\r\n\t\t  axis = a.y;\r\n\t\t  style.color = axis.options.color || options.grid.color;\r\n\t\t  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){\r\n\t\t    tick = axis.ticks[i];\r\n\t\t    if (!tick.label || tick.label.length == 0) continue;\r\n        \r\n        style.angle = Flotr.toRad(axis.options.labelsAngle);\r\n        style.halign = 'r';\r\n        style.valign = 'm';\r\n        \r\n\t\t    ctx.drawText(\r\n\t\t      tick.label,\r\n\t\t      this.plotOffset.left - options.grid.labelMargin, \r\n\t\t      this.plotOffset.top + this.tVert(tick.v, axis),\r\n\t\t      style\r\n\t\t    );\r\n\t\t  }\r\n\t\t  \r\n\t\t  // Add y2 labels.\r\n\t\t  axis = a.y2;\r\n\t\t  style.color = axis.options.color || options.grid.color;\r\n\t\t  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){\r\n\t\t    tick = axis.ticks[i];\r\n\t\t    if (!tick.label || tick.label.length == 0) continue;\r\n        \r\n        style.angle = Flotr.toRad(axis.options.labelsAngle);\r\n        style.halign = 'l';\r\n        style.valign = 'm';\r\n        \r\n\t\t    ctx.drawText(\r\n\t\t      tick.label,\r\n\t\t      this.plotOffset.left + this.plotWidth + options.grid.labelMargin, \r\n\t\t      this.plotOffset.top + this.tVert(tick.v, axis),\r\n\t\t      style\r\n\t\t    );\r\n\t\t    \r\n\t\t\t\tctx.save();\r\n\t\t\t\tctx.strokeStyle = style.color;\r\n\t\t\t\tctx.beginPath();\r\n\t\t\t\tctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));\r\n\t\t\t\tctx.lineTo(this.plotOffset.left + this.plotWidth,     this.plotOffset.top + this.tVert(tick.v, axis));\r\n\t\t\t\tctx.stroke();\r\n\t\t\t\tctx.restore();\r\n\t\t  }\r\n\t\t} \r\n\t\telse if (a.x.options.showLabels || \r\n\t\t\t\t     a.x2.options.showLabels || \r\n\t\t\t\t     a.y.options.showLabels || \r\n\t\t\t\t     a.y2.options.showLabels) {\r\n\t\t\thtml = ['<div style=\"font-size:smaller;color:' + options.grid.color + ';\" class=\"flotr-labels\">'];\r\n\t\t\t\r\n\t\t\t// Add x labels.\r\n\t\t\taxis = a.x;\r\n\t\t\tif (axis.options.showLabels){\r\n\t\t\t\tfor(i = 0; i < axis.ticks.length; ++i){\r\n\t\t\t\t\ttick = axis.ticks[i];\r\n\t\t\t\t\tif(!tick.label || tick.label.length == 0) continue;\r\n\t\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'\" class=\"flotr-grid-label\">' + tick.label + '</div>');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add x2 labels.\r\n\t\t\taxis = a.x2;\r\n\t\t\tif (axis.options.showLabels && axis.used){\r\n\t\t\t\tfor(i = 0; i < axis.ticks.length; ++i){\r\n\t\t\t\t\ttick = axis.ticks[i];\r\n\t\t\t\t\tif(!tick.label || tick.label.length == 0) continue;\r\n\t\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top - options.grid.labelMargin - axis.maxLabel.height) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'\" class=\"flotr-grid-label\">' + tick.label + '</div>');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add y labels.\r\n\t\t\taxis = a.y;\r\n\t\t\tif (axis.options.showLabels){\r\n\t\t\t\tfor(i = 0; i < axis.ticks.length; ++i){\r\n\t\t\t\t\ttick = axis.ticks[i];\r\n\t\t\t\t\tif (!tick.label || tick.label.length == 0) continue;\r\n\t\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;left:0;width:' + (this.plotOffset.left - options.grid.labelMargin) + 'px;text-align:right;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'\" class=\"flotr-grid-label\">' + tick.label + '</div>');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add y2 labels.\r\n\t\t\taxis = a.y2;\r\n\t\t\tif (axis.options.showLabels && axis.used){\r\n\t\t\t\tctx.save();\r\n\t\t\t\tctx.strokeStyle = axis.options.color || options.grid.color;\r\n\t\t\t\tctx.beginPath();\r\n\t\t\t\t\r\n\t\t\t\tfor(i = 0; i < axis.ticks.length; ++i){\r\n\t\t\t\t\ttick = axis.ticks[i];\r\n\t\t\t\t\tif (!tick.label || tick.label.length == 0) continue;\r\n\t\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;right:0;width:' + (this.plotOffset.right - options.grid.labelMargin) + 'px;text-align:left;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'\" class=\"flotr-grid-label\">' + tick.label + '</div>');\r\n\r\n\t\t\t\t\tctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));\r\n\t\t\t\t\tctx.lineTo(this.plotOffset.left + this.plotWidth,     this.plotOffset.top + this.tVert(tick.v, axis));\r\n\t\t\t\t}\r\n\t\t\t\tctx.stroke();\r\n\t\t\t\tctx.restore();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\thtml.push('</div>');\r\n\t\t\tthis.el.insert(html.join(''));\r\n\t\t}\r\n\t},\r\n  /**\r\n   * Draws the title and the subtitle\r\n   */   \r\n  drawTitles: function(){\r\n    var html,\r\n        options = this.options,\r\n        margin = options.grid.labelMargin,\r\n        ctx = this.ctx,\r\n        a = this.axes;\r\n      \r\n    if (!options.HtmlText && this.textEnabled) {\r\n      var style = {\r\n        size: options.fontSize,\r\n        color: options.grid.color,\r\n        halign: 'c'\r\n      };\r\n\r\n      // Add subtitle\r\n      if (options.subtitle){\r\n        ctx.drawText(\r\n          options.subtitle,\r\n          this.plotOffset.left + this.plotWidth/2, \r\n          this.titleHeight + this.subtitleHeight - 2,\r\n          style\r\n        );\r\n      }\r\n      \r\n\t\t\tstyle.weight = 1.5;\r\n      style.size *= 1.5;\r\n      \r\n      // Add title\r\n      if (options.title){\r\n        ctx.drawText(\r\n          options.title,\r\n          this.plotOffset.left + this.plotWidth/2, \r\n          this.titleHeight - 2,\r\n          style\r\n        );\r\n      }\r\n      \r\n      style.weight = 1.8;\r\n      style.size *= 0.8;\r\n      style.adjustAlign = true;\r\n      \r\n\t\t\t// Add x axis title\r\n\t\t\tif (a.x.options.title && a.x.used){\r\n\t\t\t\tstyle.halign = 'c';\r\n\t\t\t\tstyle.valign = 't';\r\n\t\t\t\tstyle.angle = Flotr.toRad(a.x.options.titleAngle);\r\n        ctx.drawText(\r\n          a.x.options.title,\r\n          this.plotOffset.left + this.plotWidth/2, \r\n          this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin,\r\n          style\r\n        );\r\n      }\r\n\t\t\t\r\n\t\t\t// Add x2 axis title\r\n\t\t\tif (a.x2.options.title && a.x2.used){\r\n\t\t\t\tstyle.halign = 'c';\r\n\t\t\t\tstyle.valign = 'b';\r\n\t\t\t\tstyle.angle = Flotr.toRad(a.x2.options.titleAngle);\r\n        ctx.drawText(\r\n          a.x2.options.title,\r\n          this.plotOffset.left + this.plotWidth/2, \r\n          this.plotOffset.top - a.x2.maxLabel.height - 2 * margin,\r\n          style\r\n        );\r\n      }\r\n\t\t\t\r\n\t\t\t// Add y axis title\r\n\t\t\tif (a.y.options.title && a.y.used){\r\n\t\t\t\tstyle.halign = 'r';\r\n\t\t\t\tstyle.valign = 'm';\r\n\t\t\t\tstyle.angle = Flotr.toRad(a.y.options.titleAngle);\r\n        ctx.drawText(\r\n          a.y.options.title,\r\n          this.plotOffset.left - a.y.maxLabel.width - 2 * margin, \r\n          this.plotOffset.top + this.plotHeight / 2,\r\n          style\r\n        );\r\n      }\r\n\t\t\t\r\n\t\t\t// Add y2 axis title\r\n\t\t\tif (a.y2.options.title && a.y2.used){\r\n\t\t\t\tstyle.halign = 'l';\r\n\t\t\t\tstyle.valign = 'm';\r\n\t\t\t\tstyle.angle = Flotr.toRad(a.y2.options.titleAngle);\r\n        ctx.drawText(\r\n          a.y2.options.title,\r\n          this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, \r\n          this.plotOffset.top + this.plotHeight / 2,\r\n          style\r\n        );\r\n      }\r\n    } \r\n    else {\r\n      html = ['<div style=\"color:'+options.grid.color+';\" class=\"flotr-titles\">'];\r\n      \r\n      // Add title\r\n      if (options.title){\r\n        html.push('<div style=\"position:absolute;top:0;left:'+this.plotOffset.left+'px;font-size:1em;font-weight:bold;text-align:center;width:'+this.plotWidth+'px;\" class=\"flotr-title\">'+options.title+'</div>');\r\n      }\r\n      \r\n      // Add subtitle\r\n      if (options.subtitle){\r\n        html.push('<div style=\"position:absolute;top:'+this.titleHeight+'px;left:'+this.plotOffset.left+'px;font-size:smaller;text-align:center;width:'+this.plotWidth+'px;\" class=\"flotr-subtitle\">'+options.subtitle+'</div>');\r\n      }\r\n      html.push('</div>');\r\n      \r\n      \r\n      html.push('<div class=\"flotr-axis-title\" style=\"font-weight:bold;\">');\r\n\t\t\t// Add x axis title\r\n\t\t\tif (a.x.options.title && a.x.used){\r\n\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin + a.x.titleSize.height) + 'px;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;\" class=\"flotr-axis-title\">' + a.x.options.title + '</div>');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add x2 axis title\r\n\t\t\tif (a.x2.options.title && a.x2.used){\r\n\t\t\t\thtml.push('<div style=\"position:absolute;top:0;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;\" class=\"flotr-axis-title\">' + a.x2.options.title + '</div>');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add y axis title\r\n\t\t\tif (a.y.options.title && a.y.used){\r\n\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;left:0;text-align:right;\" class=\"flotr-axis-title\">' + a.y.options.title + '</div>');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Add y2 axis title\r\n\t\t\tif (a.y2.options.title && a.y2.used){\r\n\t\t\t\thtml.push('<div style=\"position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;right:0;text-align:right;\" class=\"flotr-axis-title\">' + a.y2.options.title + '</div>');\r\n\t\t\t}\r\n\t\t\thtml.push('</div>');\r\n      \r\n      this.el.insert(html.join(''));\r\n    }\r\n  },\r\n\t/**\r\n\t * Actually draws the graph.\r\n\t * @param {Object} series - series to draw\r\n\t */\r\n\tdrawSeries: function(series){\r\n\t\tseries = series || this.series;\r\n\t\t\r\n\t\tvar drawn = false;\r\n\t\tfor(var type in Flotr._registeredTypes){\r\n\t\t\tif(series[type] && series[type].show){\r\n\t\t\t\tthis[Flotr._registeredTypes[type]](series);\r\n\t\t\t\tdrawn = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tif(!drawn){\r\n\t\t\tthis[Flotr._registeredTypes[this.options.defaultType]](series);\r\n\t\t}\r\n\t},\r\n\t\r\n\tplotLine: function(series, offset){\r\n\t\tvar ctx = this.ctx,\r\n\t\t    xa = series.xaxis,\r\n\t\t    ya = series.yaxis,\r\n  \t\t\ttHoz = this.tHoz.bind(this),\r\n  \t\t\ttVert = this.tVert.bind(this),\r\n  \t\t\tdata = series.data;\r\n\t\t\t\r\n\t\tif(data.length < 2) return;\r\n\r\n\t\tvar prevx = tHoz(data[0][0], xa),\r\n\t\t    prevy = tVert(data[0][1], ya) + offset;\r\n\r\n\t\tctx.beginPath();\r\n\t\tctx.moveTo(prevx, prevy);\r\n\t\tfor(var i = 0; i < data.length - 1; ++i){\r\n\t\t\tvar x1 = data[i][0],   y1 = data[i][1],\r\n\t\t\t    x2 = data[i+1][0], y2 = data[i+1][1];\r\n\r\n      // To allow empty values\r\n      if (y1 === null || y2 === null) continue;\r\n      \r\n\t\t\t/**\r\n\t\t\t * Clip with ymin.\r\n\t\t\t */\r\n\t\t\tif(y1 <= y2 && y1 < ya.min){\r\n\t\t\t\t/**\r\n\t\t\t\t * Line segment is outside the drawing area.\r\n\t\t\t\t */\r\n\t\t\t\tif(y2 < ya.min) continue;\r\n\t\t\t\t\r\n\t\t\t\t/**\r\n\t\t\t\t * Compute new intersection point.\r\n\t\t\t\t */\r\n\t\t\t\tx1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty1 = ya.min;\r\n\t\t\t}else if(y2 <= y1 && y2 < ya.min){\r\n\t\t\t\tif(y1 < ya.min) continue;\r\n\t\t\t\tx2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty2 = ya.min;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Clip with ymax.\r\n\t\t\t */ \r\n\t\t\tif(y1 >= y2 && y1 > ya.max) {\r\n\t\t\t\tif(y2 > ya.max) continue;\r\n\t\t\t\tx1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty1 = ya.max;\r\n\t\t\t}\r\n\t\t\telse if(y2 >= y1 && y2 > ya.max){\r\n\t\t\t\tif(y1 > ya.max) continue;\r\n\t\t\t\tx2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty2 = ya.max;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Clip with xmin.\r\n\t\t\t */\r\n\t\t\tif(x1 <= x2 && x1 < xa.min){\r\n\t\t\t\tif(x2 < xa.min) continue;\r\n\t\t\t\ty1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx1 = xa.min;\r\n\t\t\t}else if(x2 <= x1 && x2 < xa.min){\r\n\t\t\t\tif(x1 < xa.min) continue;\r\n\t\t\t\ty2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx2 = xa.min;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Clip with xmax.\r\n\t\t\t */\r\n\t\t\tif(x1 >= x2 && x1 > xa.max){\r\n\t\t\t\tif (x2 > xa.max) continue;\r\n\t\t\t\ty1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx1 = xa.max;\r\n\t\t\t}else if(x2 >= x1 && x2 > xa.max){\r\n\t\t\t\tif(x1 > xa.max) continue;\r\n\t\t\t\ty2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx2 = xa.max;\r\n\t\t\t}\r\n\r\n\t\t\tif(prevx != tHoz(x1, xa) || prevy != tVert(y1, ya) + offset)\r\n\t\t\t\tctx.moveTo(tHoz(x1, xa), tVert(y1, ya) + offset);\r\n\t\t\t\r\n\t\t\tprevx = tHoz(x2, xa);\r\n\t\t\tprevy = tVert(y2, ya) + offset;\r\n\t\t\tctx.lineTo(prevx, prevy);\r\n\t\t}\r\n\t\tctx.stroke();\r\n\t},\r\n\t/**\r\n\t * Function used to fill\r\n\t * @param {Object} data\r\n\t */\r\n\tplotLineArea: function(series, offset){\r\n\t\tvar data = series.data;\r\n\t\tif(data.length < 2) return;\r\n\r\n\t\tvar top, lastX = 0,\r\n\t\t\tctx = this.ctx,\r\n\t    xa = series.xaxis,\r\n\t    ya = series.yaxis,\r\n\t\t\ttHoz = this.tHoz.bind(this),\r\n\t\t\ttVert = this.tVert.bind(this),\r\n\t\t\tbottom = Math.min(Math.max(0, ya.min), ya.max),\r\n\t\t\tfirst = true;\r\n\t\t\r\n\t\tctx.beginPath();\r\n\t\tfor(var i = 0; i < data.length - 1; ++i){\r\n\t\t\t\r\n\t\t\tvar x1 = data[i][0], y1 = data[i][1],\r\n\t\t\t    x2 = data[i+1][0], y2 = data[i+1][1];\r\n\t\t\t\r\n\t\t\tif(x1 <= x2 && x1 < xa.min){\r\n\t\t\t\tif(x2 < xa.min) continue;\r\n\t\t\t\ty1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx1 = xa.min;\r\n\t\t\t}else if(x2 <= x1 && x2 < xa.min){\r\n\t\t\t\tif(x1 < xa.min) continue;\r\n\t\t\t\ty2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx2 = xa.min;\r\n\t\t\t}\r\n\t\t\t\t\t\t\t\t\r\n\t\t\tif(x1 >= x2 && x1 > xa.max){\r\n\t\t\t\tif(x2 > xa.max) continue;\r\n\t\t\t\ty1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx1 = xa.max;\r\n\t\t\t}else if(x2 >= x1 && x2 > xa.max){\r\n\t\t\t\tif (x1 > xa.max) continue;\r\n\t\t\t\ty2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;\r\n\t\t\t\tx2 = xa.max;\r\n\t\t\t}\r\n\r\n\t\t\tif(first){\r\n\t\t\t\tctx.moveTo(tHoz(x1, xa), tVert(bottom, ya) + offset);\r\n\t\t\t\tfirst = false;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t/**\r\n\t\t\t * Now check the case where both is outside.\r\n\t\t\t */\r\n\t\t\tif(y1 >= ya.max && y2 >= ya.max){\r\n\t\t\t\tctx.lineTo(tHoz(x1, xa), tVert(ya.max, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(x2, xa), tVert(ya.max, ya) + offset);\r\n\t\t\t\tcontinue;\r\n\t\t\t}else if(y1 <= ya.min && y2 <= ya.min){\r\n\t\t\t\tctx.lineTo(tHoz(x1, xa), tVert(ya.min, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(x2, xa), tVert(ya.min, ya) + offset);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t/**\r\n\t\t\t * Else it's a bit more complicated, there might\r\n\t\t\t * be two rectangles and two triangles we need to fill\r\n\t\t\t * in; to find these keep track of the current x values.\r\n\t\t\t */\r\n\t\t\tvar x1old = x1, x2old = x2;\r\n\t\t\t\r\n\t\t\t/**\r\n\t\t\t * And clip the y values, without shortcutting.\r\n\t\t\t * Clip with ymin.\r\n\t\t\t */\r\n\t\t\tif(y1 <= y2 && y1 < ya.min && y2 >= ya.min){\r\n\t\t\t\tx1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty1 = ya.min;\r\n\t\t\t}else if(y2 <= y1 && y2 < ya.min && y1 >= ya.min){\r\n\t\t\t\tx2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty2 = ya.min;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Clip with ymax.\r\n\t\t\t */\r\n\t\t\tif(y1 >= y2 && y1 > ya.max && y2 <= ya.max){\r\n\t\t\t\tx1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty1 = ya.max;\r\n\t\t\t}else if(y2 >= y1 && y2 > ya.max && y1 <= ya.max){\r\n\t\t\t\tx2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;\r\n\t\t\t\ty2 = ya.max;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * If the x value was changed we got a rectangle to fill.\r\n\t\t\t */\r\n\t\t\tif(x1 != x1old){\r\n\t\t\t\ttop = (y1 <= ya.min) ? top = ya.min : ya.max;\r\n\t\t\t\tctx.lineTo(tHoz(x1old, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(x1, xa), tVert(top, ya) + offset);\r\n\t\t\t}\r\n\t\t   \t\r\n\t\t\t/**\r\n\t\t\t * Fill the triangles.\r\n\t\t\t */\r\n\t\t\tctx.lineTo(tHoz(x1, xa), tVert(y1, ya) + offset);\r\n\t\t\tctx.lineTo(tHoz(x2, xa), tVert(y2, ya) + offset);\r\n\r\n\t\t\t/**\r\n\t\t\t * Fill the other rectangle if it's there.\r\n\t\t\t */\r\n\t\t\tif(x2 != x2old){\r\n\t\t\t\ttop = (y2 <= ya.min) ? ya.min : ya.max;\r\n\t\t\t\tctx.lineTo(tHoz(x2old, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(x2, xa), tVert(top, ya) + offset);\r\n\t\t\t}\r\n\r\n\t\t\tlastX = Math.max(x2, x2old);\r\n\t\t}\r\n\t\t\r\n\t\tctx.lineTo(tHoz(lastX, xa), tVert(bottom, ya) + offset);\r\n\t\tctx.closePath();\r\n\t\tctx.fill();\r\n\t},\r\n\t/**\r\n\t * Function: (private) drawSeriesLines\r\n\t * \r\n\t * Function draws lines series in the canvas element.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tseries - Series with options.lines.show = true.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tdrawSeriesLines: function(series){\r\n\t\tseries = series || this.series;\r\n\t\tvar ctx = this.ctx;\r\n\t\tctx.save();\r\n\t\tctx.translate(this.plotOffset.left, this.plotOffset.top);\r\n\t\tctx.lineJoin = 'round';\r\n\r\n\t\tvar lw = series.lines.lineWidth;\r\n\t\tvar sw = series.shadowSize;\r\n\r\n\t\tif(sw > 0){\r\n\t\t\tctx.lineWidth = sw / 2;\r\n\r\n\t\t\tvar offset = lw/2 + ctx.lineWidth/2;\r\n\t\t\t\r\n\t\t\tctx.strokeStyle = \"rgba(0,0,0,0.1)\";\r\n\t\t\tthis.plotLine(series, offset + sw/2);\r\n\r\n\t\t\tctx.strokeStyle = \"rgba(0,0,0,0.2)\";\r\n\t\t\tthis.plotLine(series, offset);\r\n\r\n\t\t\tif(series.lines.fill) {\r\n\t\t\t\tctx.fillStyle = \"rgba(0,0,0,0.05)\";\r\n\t\t\t\tthis.plotLineArea(series, offset + sw/2);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tctx.lineWidth = lw;\r\n\t\tctx.strokeStyle = series.color;\r\n\t\tif(series.lines.fill){\r\n\t\t\tctx.fillStyle = series.lines.fillColor != null ? series.lines.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.lines.fillOpacity).toString();\r\n\t\t\tthis.plotLineArea(series, 0);\r\n\t\t}\r\n\r\n\t\tthis.plotLine(series, 0);\r\n\t\tctx.restore();\r\n\t},\r\n\t/**\r\n\t * Function: drawSeriesPoints\r\n\t * \r\n\t * Function draws point series in the canvas element.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tseries - Series with options.points.show = true.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tdrawSeriesPoints: function(series) {\r\n\t\tvar ctx = this.ctx;\r\n\t\t\r\n\t\tctx.save();\r\n\t\tctx.translate(this.plotOffset.left, this.plotOffset.top);\r\n\r\n\t\tvar lw = series.lines.lineWidth;\r\n\t\tvar sw = series.shadowSize;\r\n\t\t\r\n\t\tif(sw > 0){\r\n\t\t\tctx.lineWidth = sw / 2;\r\n      \r\n\t\t\tctx.strokeStyle = 'rgba(0,0,0,0.1)';\r\n\t\t\tthis.plotPointShadows(series, sw/2 + ctx.lineWidth/2, series.points.radius);\r\n\r\n\t\t\tctx.strokeStyle = 'rgba(0,0,0,0.2)';\r\n\t\t\tthis.plotPointShadows(series, ctx.lineWidth/2, series.points.radius);\r\n\t\t}\r\n\r\n\t\tctx.lineWidth = series.points.lineWidth;\r\n\t\tctx.strokeStyle = series.color;\r\n\t\tctx.fillStyle = series.points.fillColor != null ? series.points.fillColor : series.color;\r\n\t\tthis.plotPoints(series, series.points.radius, series.points.fill);\r\n\t\tctx.restore();\r\n\t},\r\n\tplotPoints: function (series, radius, fill) {\r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n\t\t    ctx = this.ctx, i,\r\n\t\t    data = series.data;\r\n\t\t\t\r\n\t\tfor(i = data.length - 1; i > -1; --i){\r\n\t\t\tvar x = data[i][0], y = data[i][1];\r\n\t\t\tif(x < xa.min || x > xa.max || y < ya.min || y > ya.max)\r\n\t\t\t\tcontinue;\r\n\t\t\t\r\n\t\t\tctx.beginPath();\r\n\t\t\tctx.arc(this.tHoz(x, xa), this.tVert(y, ya), radius, 0, 2 * Math.PI, true);\r\n\t\t\tif(fill) ctx.fill();\r\n\t\t\tctx.stroke();\r\n\t\t}\r\n\t},\r\n\tplotPointShadows: function(series, offset, radius){\r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n\t\t    ctx = this.ctx, i,\r\n\t\t    data = series.data;\r\n\t\t\t\r\n\t\tfor(i = data.length - 1; i > -1; --i){\r\n\t\t\tvar x = data[i][0], y = data[i][1];\r\n\t\t\tif (x < xa.min || x > xa.max || y < ya.min || y > ya.max)\r\n\t\t\t\tcontinue;\r\n\t\t\tctx.beginPath();\r\n\t\t\tctx.arc(this.tHoz(x, xa), this.tVert(y, ya) + offset, radius, 0, Math.PI, false);\r\n\t\t\tctx.stroke();\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Function: drawSeriesBars\r\n\t * \r\n\t * Function draws bar series in the canvas element.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tseries - Series with options.bars.show = true.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tdrawSeriesBars: function(series) {\r\n\t\tvar ctx = this.ctx,\r\n\t\t\tbw = series.bars.barWidth,\r\n\t\t\tlw = Math.min(series.bars.lineWidth, bw);\r\n\t\t\r\n\t\tctx.save();\r\n\t\tctx.translate(this.plotOffset.left, this.plotOffset.top);\r\n\t\tctx.lineJoin = 'miter';\r\n\r\n\t\t/**\r\n\t\t * @todo linewidth not interpreted the right way.\r\n\t\t */\r\n\t\tctx.lineWidth = lw;\r\n\t\tctx.strokeStyle = series.color;\r\n    \r\n\t\tthis.plotBarsShadows(series, bw, 0, series.bars.fill);\r\n\r\n\t\tif(series.bars.fill){\r\n\t\t\tctx.fillStyle = series.bars.fillColor != null ? series.bars.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.bars.fillOpacity).toString();\r\n\t\t}\r\n    \r\n\t\tthis.plotBars(series, bw, 0, series.bars.fill);\r\n\t\tctx.restore();\r\n\t},\r\n\tplotBars: function(series, barWidth, offset, fill){\r\n\t\tvar data = series.data;\r\n\t\tif(data.length < 1) return;\r\n\t\t\r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n  \t\t\tctx = this.ctx,\r\n  \t\t\ttHoz = this.tHoz.bind(this),\r\n  \t\t\ttVert = this.tVert.bind(this);\r\n\r\n\t\tfor(var i = 0; i < data.length; i++){\r\n\t\t\tvar x = data[i][0],\r\n\t\t\t    y = data[i][1];\r\n\t\t\tvar drawLeft = true, drawTop = true, drawRight = true;\r\n\t\t\t\r\n\t\t\t// Stacked bars\r\n\t\t\tvar stackOffset = 0;\r\n\t\t\tif(series.bars.stacked) {\r\n\t\t\t  xa.values.each(function(o, v) {\r\n\t\t\t    if (v == x) {\r\n\t\t\t      stackOffset = o.stack || 0;\r\n\t\t\t      o.stack = stackOffset + y;\r\n\t\t\t    }\r\n\t\t\t  });\r\n\t\t\t}\r\n\r\n\t\t\t// @todo: fix horizontal bars support\r\n\t\t\t// Horizontal bars\r\n\t\t\tif(series.bars.horizontal)\r\n\t\t\t\tvar left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;\r\n\t\t\telse \r\n\t\t\t\tvar left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;\r\n\r\n\t\t\tif(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif(left < xa.min){\r\n\t\t\t\tleft = xa.min;\r\n\t\t\t\tdrawLeft = false;\r\n\t\t\t}\r\n\r\n\t\t\tif(right > xa.max){\r\n\t\t\t\tright = xa.max;\r\n\t\t\t\tif (xa.lastSerie != series && series.bars.horizontal)\r\n\t\t\t\t\tdrawTop = false;\r\n\t\t\t}\r\n\r\n\t\t\tif(bottom < ya.min)\r\n\t\t\t\tbottom = ya.min;\r\n\r\n\t\t\tif(top > ya.max){\r\n\t\t\t\ttop = ya.max;\r\n\t\t\t\tif (ya.lastSerie != series && !series.bars.horizontal)\r\n\t\t\t\t\tdrawTop = false;\r\n\t\t\t}\r\n      \r\n\t\t\t/**\r\n\t\t\t * Fill the bar.\r\n\t\t\t */\r\n\t\t\tif(fill){\r\n\t\t\t\tctx.beginPath();\r\n\t\t\t\tctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(left, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(right, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx.lineTo(tHoz(right, xa), tVert(bottom, ya) + offset);\r\n\t\t\t\tctx.fill();\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Draw bar outline/border.\r\n\t\t\t */\r\n\t\t\tif(series.bars.lineWidth != 0 && (drawLeft || drawRight || drawTop)){\r\n\t\t\t\tctx.beginPath();\r\n\t\t\t\tctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);\r\n\t\t\t\t\r\n\t\t\t\tctx[drawLeft ?'lineTo':'moveTo'](tHoz(left, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx[drawTop  ?'lineTo':'moveTo'](tHoz(right, xa), tVert(top, ya) + offset);\r\n\t\t\t\tctx[drawRight?'lineTo':'moveTo'](tHoz(right, xa), tVert(bottom, ya) + offset);\r\n\t\t\t\t         \r\n\t\t\t\tctx.stroke();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n  plotBarsShadows: function(series, barWidth, offset){\r\n\t\tvar data = series.data;\r\n    if(data.length < 1) return;\r\n    \r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n        ctx = this.ctx,\r\n        tHoz = this.tHoz.bind(this),\r\n        tVert = this.tVert.bind(this),\r\n        sw = this.options.shadowSize;\r\n\r\n    for(var i = 0; i < data.length; i++){\r\n      var x = data[i][0],\r\n          y = data[i][1];\r\n      \r\n      // Stacked bars\r\n      var stackOffset = 0;\r\n\t\t\tif(series.bars.stacked) {\r\n\t\t\t  xa.values.each(function(o, v) {\r\n\t\t\t    if (v == x) {\r\n\t\t\t      stackOffset = o.stackShadow || 0;\r\n\t\t\t      o.stackShadow = stackOffset + y;\r\n\t\t\t    }\r\n\t\t\t  });\r\n\t\t\t}\r\n      \r\n      // Horizontal bars\r\n      if(series.bars.horizontal) \r\n        var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;\r\n      else \r\n        var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;\r\n\r\n      if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)\r\n        continue;\r\n\r\n      if(left < xa.min)   left = xa.min;\r\n      if(right > xa.max)  right = xa.max;\r\n      if(bottom < ya.min) bottom = ya.min;\r\n      if(top > ya.max)    top = ya.max;\r\n      \r\n      var width =  tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);\r\n      var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));\r\n\r\n      ctx.fillStyle = 'rgba(0,0,0,0.05)';\r\n      ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);\r\n    }\r\n  },\r\n\t/**\r\n\t * Function: drawSeriesCandles\r\n\t * \r\n\t * Function draws candles series in the canvas element.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tseries - Series with options.candles.show = true.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tdrawSeriesCandles: function(series) {\r\n\t\tvar ctx = this.ctx,\r\n\t\t\t  bw = series.candles.candleWidth;\r\n\t\t\r\n\t\tctx.save();\r\n\t\tctx.translate(this.plotOffset.left, this.plotOffset.top);\r\n\t\tctx.lineJoin = 'miter';\r\n\r\n\t\t/**\r\n\t\t * @todo linewidth not interpreted the right way.\r\n\t\t */\r\n\t\tctx.lineWidth = series.candles.lineWidth;\r\n\t\tthis.plotCandlesShadows(series, bw/2);\r\n\t\tthis.plotCandles(series, bw/2);\r\n\t\t\r\n\t\tctx.restore();\r\n\t},\r\n\tplotCandles: function(series, offset){\r\n\t\tvar data = series.data;\r\n\t\tif(data.length < 1) return;\r\n\t\t\r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n  \t\t\tctx = this.ctx,\r\n  \t\t\ttHoz = this.tHoz.bind(this),\r\n  \t\t\ttVert = this.tVert.bind(this);\r\n\r\n\t\tfor(var i = 0; i < data.length; i++){\r\n      var d     = data[i],\r\n  \t\t    x     = d[0],\r\n  \t\t    open  = d[1],\r\n  \t\t    high  = d[2],\r\n  \t\t    low   = d[3],\r\n  \t\t    close = d[4];\r\n\r\n\t\t\tvar left    = x,\r\n\t\t\t    right   = x + series.candles.candleWidth,\r\n          bottom  = Math.max(ya.min, low),\r\n\t        top     = Math.min(ya.max, high),\r\n          bottom2 = Math.max(ya.min, Math.min(open, close)),\r\n\t        top2    = Math.min(ya.max, Math.max(open, close));\r\n\r\n\t\t\tif(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tvar color = series.candles[open>close?'downFillColor':'upFillColor'];\r\n\t\t\t/**\r\n\t\t\t * Fill the candle.\r\n\t\t\t */\r\n\t\t\tif(series.candles.fill && !series.candles.barcharts){\r\n\t\t\t\tctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.candles.fillOpacity).toString();\r\n\t\t\t\tctx.fillRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Draw candle outline/border, high, low.\r\n\t\t\t */\r\n\t\t\tif(series.candles.lineWidth || series.candles.wickLineWidth){\r\n\t\t\t\tvar x, y, pixelOffset = (series.candles.wickLineWidth % 2) / 2;\r\n\r\n\t\t\t\tx = Math.floor(tHoz((left + right) / 2), xa) + pixelOffset;\r\n\t\t\t\t\r\n\t\t\t  ctx.save();\r\n\t\t\t  ctx.strokeStyle = color;\r\n\t\t\t  ctx.lineWidth = series.candles.wickLineWidth;\r\n\t\t\t  ctx.lineCap = 'butt';\r\n\t\t\t  \r\n\t\t\t\tif (series.candles.barcharts) {\r\n\t\t\t\t\tctx.beginPath();\r\n\t\t\t\t\t\r\n\t\t\t\t\tctx.moveTo(x, Math.floor(tVert(top, ya) + offset));\r\n\t\t\t\t\tctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));\r\n\t\t\t\t\t\r\n\t\t\t\t\ty = Math.floor(tVert(open, ya) + offset)+0.5;\r\n\t\t\t\t\tctx.moveTo(Math.floor(tHoz(left, xa))+pixelOffset, y);\r\n\t\t\t\t\tctx.lineTo(x, y);\r\n\t\t\t\t\t\r\n\t\t\t\t\ty = Math.floor(tVert(close, ya) + offset)+0.5;\r\n\t\t\t\t\tctx.moveTo(Math.floor(tHoz(right, xa))+pixelOffset, y);\r\n\t\t\t\t\tctx.lineTo(x, y);\r\n\t\t\t\t} \r\n\t\t\t\telse {\r\n  \t\t\t\tctx.strokeRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));\r\n\r\n  \t\t\t\tctx.beginPath();\r\n  \t\t\t\tctx.moveTo(x, Math.floor(tVert(top2,    ya) + offset));\r\n  \t\t\t\tctx.lineTo(x, Math.floor(tVert(top,     ya) + offset));\r\n  \t\t\t\tctx.moveTo(x, Math.floor(tVert(bottom2, ya) + offset));\r\n  \t\t\t\tctx.lineTo(x, Math.floor(tVert(bottom,  ya) + offset));\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tctx.stroke();\r\n\t\t\t\tctx.restore();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n  plotCandlesShadows: function(series, offset){\r\n\t\tvar data = series.data;\r\n    if(data.length < 1 || series.candles.barcharts) return;\r\n    \r\n    var xa = series.xaxis,\r\n        ya = series.yaxis,\r\n        tHoz = this.tHoz.bind(this),\r\n        tVert = this.tVert.bind(this),\r\n        sw = this.options.shadowSize;\r\n\r\n    for(var i = 0; i < data.length; i++){\r\n      var d     = data[i],\r\n      \t\tx     = d[0],\r\n\t        open  = d[1],\r\n\t        high  = d[2],\r\n\t        low   = d[3],\r\n\t        close = d[4];\r\n      \r\n\t\t\tvar left   = x,\r\n\t        right  = x + series.candles.candleWidth,\r\n          bottom = Math.max(ya.min, Math.min(open, close)),\r\n\t        top    = Math.min(ya.max, Math.max(open, close));\r\n\r\n      if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)\r\n        continue;\r\n\r\n      var width =  tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);\r\n      var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));\r\n\r\n      this.ctx.fillStyle = 'rgba(0,0,0,0.05)';\r\n      this.ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);\r\n    }\r\n  },\r\n  /**\r\n   * Function: drawSeriesPie\r\n   * \r\n   * Function draws a pie in the canvas element.\r\n   * \r\n   * Parameters:\r\n   *    series - Series with options.pie.show = true.\r\n   * \r\n   * Returns:\r\n   *    void\r\n   */\r\n  drawSeriesPie: function(series) {\r\n    if (!this.options.pie.drawn) {\r\n    var ctx = this.ctx,\r\n        options = this.options,\r\n        lw = series.pie.lineWidth,\r\n        sw = series.shadowSize,\r\n        data = series.data,\r\n        radius = (Math.min(this.canvasWidth, this.canvasHeight) * series.pie.sizeRatio) / 2,\r\n        html = [];\r\n    \r\n    var vScale = 1;//Math.cos(series.pie.viewAngle);\r\n    var plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;\r\n    \r\n    var style = {\r\n      size: options.fontSize*1.2,\r\n      color: options.grid.color,\r\n      weight: 1.5\r\n    };\r\n    \r\n    var center = {\r\n      x: (this.canvasWidth+this.plotOffset.left)/2,\r\n      y: (this.canvasHeight-this.plotOffset.bottom)/2\r\n    };\r\n    \r\n    // Pie portions\r\n    var portions = this.series.collect(function(hash, index){\r\n    \tif (hash.pie.show)\r\n      return {\r\n        name: (hash.label || hash.data[0][1]),\r\n        value: [index, hash.data[0][1]],\r\n        explode: hash.pie.explode\r\n      };\r\n    });\r\n    \r\n    // Sum of the portions' angles\r\n    var sum = portions.pluck('value').pluck(1).inject(0, function(acc, n) { return acc + n; });\r\n    \r\n    var fraction = 0.0,\r\n        angle = series.pie.startAngle,\r\n        value = 0.0;\r\n    \r\n    var slices = portions.collect(function(slice){\r\n      angle += fraction;\r\n      value = parseFloat(slice.value[1]); // @warning : won't support null values !!\r\n      fraction = value/sum;\r\n      return {\r\n        name:     slice.name,\r\n        fraction: fraction,\r\n        x:        slice.value[0],\r\n        y:        value,\r\n        explode:  slice.explode,\r\n        startAngle: 2 * angle * Math.PI,\r\n        endAngle:   2 * (angle + fraction) * Math.PI\r\n      };\r\n    });\r\n    \r\n    ctx.save();\r\n\r\n    if(sw > 0){\r\n\t    slices.each(function (slice) {\r\n        var bisection = (slice.startAngle + slice.endAngle) / 2;\r\n        \r\n        var xOffset = center.x + Math.cos(bisection) * slice.explode + sw;\r\n        var yOffset = center.y + Math.sin(bisection) * slice.explode + sw;\r\n        \r\n\t\t    this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);\r\n\r\n        ctx.fillStyle = 'rgba(0,0,0,0.1)';\r\n        ctx.fill();\r\n      }, this);\r\n    }\r\n    \r\n    if (options.HtmlText) {\r\n      html = ['<div style=\"color:' + this.options.grid.color + '\" class=\"flotr-labels\">'];\r\n    }\r\n    \r\n    slices.each(function (slice, index) {\r\n      var bisection = (slice.startAngle + slice.endAngle) / 2;\r\n      var color = options.colors[index];\r\n      \r\n      var xOffset = center.x + Math.cos(bisection) * slice.explode;\r\n      var yOffset = center.y + Math.sin(bisection) * slice.explode;\r\n      \r\n      this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);\r\n      \r\n      if(series.pie.fill){\r\n        ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();\r\n        ctx.fill();\r\n      }\r\n      ctx.lineWidth = lw;\r\n      ctx.strokeStyle = color;\r\n      ctx.stroke();\r\n      \r\n      /*ctx.save();\r\n      ctx.scale(1, vScale);\r\n      \r\n      ctx.moveTo(xOffset, yOffset);\r\n      ctx.beginPath();\r\n      ctx.lineTo(xOffset, yOffset+plotTickness);\r\n      ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);\r\n      ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);\r\n      ctx.lineTo(xOffset, yOffset);\r\n      ctx.closePath();\r\n      ctx.fill();ctx.stroke();\r\n      \r\n      ctx.moveTo(xOffset, yOffset);\r\n      ctx.beginPath();\r\n      ctx.lineTo(xOffset, yOffset+plotTickness);\r\n      ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius+plotTickness);\r\n      ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);\r\n      ctx.lineTo(xOffset, yOffset);\r\n      ctx.closePath();\r\n      ctx.fill();ctx.stroke();\r\n      \r\n      ctx.moveTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);\r\n      ctx.beginPath();\r\n      ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);\r\n      ctx.arc(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false);\r\n      ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);\r\n      ctx.arc(xOffset, yOffset, radius, slice.endAngle, slice.startAngle, true);\r\n      ctx.closePath();\r\n      ctx.fill();ctx.stroke();\r\n      \r\n      ctx.scale(1, 1/vScale);\r\n      this.plotSlice(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false, vScale);\r\n      ctx.stroke();\r\n      if(series.pie.fill){\r\n        ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();\r\n        ctx.fill();\r\n      }\r\n      \r\n      ctx.restore();*/\r\n      \r\n      var label = options.pie.labelFormatter(slice);\r\n      \r\n      var textAlignRight = (Math.cos(bisection) < 0);\r\n      var distX = xOffset + Math.cos(bisection) * (series.pie.explode + radius);\r\n      var distY = yOffset + Math.sin(bisection) * (series.pie.explode + radius);\r\n      \r\n      if (slice.fraction && label) {\r\n        if (options.HtmlText) {\r\n          var divStyle = 'position:absolute;top:' + (distY - 5) + 'px;'; //@todo: change\r\n          if (textAlignRight) {\r\n            divStyle += 'right:'+(this.canvasWidth - distX)+'px;text-align:right;';\r\n          }\r\n          else {\r\n            divStyle += 'left:'+distX+'px;text-align:left;';\r\n          }\r\n          html.push('<div style=\"' + divStyle + '\" class=\"flotr-grid-label\">' + label + '</div>');\r\n        }\r\n        else {\r\n          style.halign = textAlignRight ? 'r' : 'l';\r\n          ctx.drawText(\r\n            label, \r\n            distX, \r\n            distY + style.size / 2, \r\n            style\r\n          );\r\n        }\r\n      }\r\n    }, this);\r\n\r\n    if (options.HtmlText) {\r\n      html.push('</div>');    \r\n      this.el.insert(html.join(''));\r\n    }\r\n    \r\n    ctx.restore();\r\n    options.pie.drawn = true;\r\n    }\r\n  },\r\n  plotSlice: function(x, y, radius, startAngle, endAngle, fill, vScale) {\r\n    var ctx = this.ctx;\r\n    vScale = vScale || 1;\r\n    \r\n    ctx.save();\r\n    ctx.scale(1, vScale);\r\n    ctx.beginPath();\r\n    ctx.moveTo(x, y);\r\n    ctx.arc   (x, y, radius, startAngle, endAngle, fill);\r\n    ctx.lineTo(x, y);\r\n    ctx.closePath();\r\n    ctx.restore();\r\n  },\r\n  plotPie: function() {}, \r\n\t/**\r\n\t * Function: insertLegend\r\n\t * \r\n\t * Function adds a legend div to the canvas container or draws it on the canvas.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tinsertLegend: function(){\r\n\t\tif(!this.options.legend.show)\r\n\t\t\treturn;\r\n\t\t\t\r\n\t\tvar series = this.series,\r\n\t\t\tplotOffset = this.plotOffset,\r\n\t\t\toptions = this.options,\r\n\t\t\tfragments = [],\r\n\t\t\trowStarted = false, \r\n\t\t\tctx = this.ctx,\r\n\t\t\ti;\r\n\t\t\t\r\n\t\tvar noLegendItems = series.findAll(function(s) {return (s.label && !s.hide)}).size();\r\n\r\n    if (noLegendItems) {\r\n\t    if (!options.HtmlText && this.textEnabled) {\r\n\t      var style = {\r\n\t        size: options.fontSize*1.1,\r\n\t        color: options.grid.color\r\n\t      };\r\n\t      \r\n\t      // @todo: take css into account\r\n\t      //var dummyDiv = this.el.insert('<div class=\"flotr-legend\" style=\"position:absolute;top:-10000px;\"></div>');\r\n\t      \r\n\t      var p = options.legend.position, \r\n\t          m = options.legend.margin,\r\n\t          lbw = options.legend.labelBoxWidth,\r\n\t          lbh = options.legend.labelBoxHeight,\r\n\t          lbm = options.legend.labelBoxMargin,\r\n\t          offsetX = plotOffset.left + m,\r\n\t          offsetY = plotOffset.top + m;\r\n\t      \r\n\t      // We calculate the labels' max width\r\n\t      var labelMaxWidth = 0;\r\n\t      for(i = series.length - 1; i > -1; --i){\r\n\t        if(!series[i].label || series[i].hide) continue;\r\n\t        var label = options.legend.labelFormatter(series[i].label);\t\r\n\t        labelMaxWidth = Math.max(labelMaxWidth, ctx.measureText(label, style));\r\n\t      }\r\n\t      \r\n\t      var legendWidth  = Math.round(lbw + lbm*3 + labelMaxWidth),\r\n\t          legendHeight = Math.round(noLegendItems*(lbm+lbh) + lbm);\r\n\t\r\n\t      if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight);\r\n\t      if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth);\r\n\r\n\t      // Legend box\r\n\t      var color = Flotr.parseColor(options.legend.backgroundColor || 'rgb(240,240,240)').scale(null, null, null, options.legend.backgroundOpacity || 0.1).toString();\r\n\t      \r\n\t      ctx.fillStyle = color;\r\n\t      ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight);\r\n\t      ctx.strokeStyle = options.legend.labelBoxBorderColor;\r\n\t      ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight);\r\n\t      \r\n\t      // Legend labels\r\n\t      var x = offsetX + lbm;\r\n\t      var y = offsetY + lbm;\r\n\t      for(i = 0; i < series.length; i++){\r\n\t        if(!series[i].label || series[i].hide) continue;\r\n\t        var label = options.legend.labelFormatter(series[i].label);\r\n\r\n\t        ctx.fillStyle = series[i].color;\r\n\t        ctx.fillRect(x, y, lbw-1, lbh-1);\r\n\t        \r\n\t        ctx.strokeStyle = options.legend.labelBoxBorderColor;\r\n\t        ctx.lineWidth = 1;\r\n\t        ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2);\r\n\t        \r\n\t        // Legend text\r\n\t        ctx.drawText(\r\n\t          label,\r\n\t          x + lbw + lbm,\r\n\t          y + (lbh + style.size - ctx.fontDescent(style))/2,\r\n\t          style\r\n\t        );\r\n\t        \r\n\t        y += lbh + lbm;\r\n\t      }\r\n\t    }\r\n\t    else {\r\n\t  \t\tfor(i = 0; i < series.length; ++i){\r\n\t  \t\t\tif(!series[i].label || series[i].hide) continue;\r\n\t  \t\t\t\r\n\t  \t\t\tif(i % options.legend.noColumns == 0){\r\n\t  \t\t\t\tfragments.push(rowStarted ? '</tr><tr>' : '<tr>');\r\n\t  \t\t\t\trowStarted = true;\r\n\t  \t\t\t}\r\n\t  \r\n\t  \t\t\tvar label = options.legend.labelFormatter(series[i].label);\r\n\t  \t\t\t\r\n\t  \t\t\tfragments.push('<td class=\"flotr-legend-color-box\"><div style=\"border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px\"><div style=\"width:' + options.legend.labelBoxWidth + 'px;height:' + options.legend.labelBoxHeight + 'px;background-color:' + series[i].color + '\"></div></div></td>' +\r\n\t  \t\t\t\t'<td class=\"flotr-legend-label\">' + label + '</td>');\r\n\t  \t\t}\r\n\t  \t\tif(rowStarted) fragments.push('</tr>');\r\n\t  \t\t\r\n\t  \t\tif(fragments.length > 0){\r\n\t  \t\t\tvar table = '<table style=\"font-size:smaller;color:' + options.grid.color + '\">' + fragments.join(\"\") + '</table>';\r\n\t  \t\t\tif(options.legend.container != null){\r\n\t  \t\t\t\t$(options.legend.container).update(table);\r\n\t  \t\t\t}else{\r\n\t  \t\t\t\tvar pos = '';\r\n\t  \t\t\t\tvar p = options.legend.position, m = options.legend.margin;\r\n\t  \t\t\t\t\r\n\t  \t\t\t\t     if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';\r\n\t  \t\t\t\telse if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';\t\t\t\t\t\r\n\t  \t\t\t\t     if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';\r\n\t  \t\t\t\telse if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';\r\n\t  \t\t\t\t     \r\n\t  \t\t\t\tvar div = this.el.insert('<div class=\"flotr-legend\" style=\"position:absolute;z-index:2;' + pos +'\">' + table + '</div>').select('div.flotr-legend').first();\r\n\t  \t\t\t\t\r\n\t  \t\t\t\tif(options.legend.backgroundOpacity != 0.0){\r\n\t  \t\t\t\t\t/**\r\n\t  \t\t\t\t\t * Put in the transparent background separately to avoid blended labels and\r\n\t  \t\t\t\t\t * label boxes.\r\n\t  \t\t\t\t\t */\r\n\t  \t\t\t\t\tvar c = options.legend.backgroundColor;\r\n\t  \t\t\t\t\tif(c == null){\r\n\t  \t\t\t\t\t\tvar tmp = (options.grid.backgroundColor != null) ? options.grid.backgroundColor : Flotr.extractColor(div);\r\n\t  \t\t\t\t\t\tc = Flotr.parseColor(tmp).adjust(null, null, null, 1).toString();\r\n\t  \t\t\t\t\t}\r\n\t  \t\t\t\t\tthis.el.insert('<div class=\"flotr-legend-bg\" style=\"position:absolute;width:' + div.getWidth() + 'px;height:' + div.getHeight() + 'px;' + pos +'background-color:' + c + ';\"> </div>').select('div.flotr-legend-bg').first().setStyle({\r\n\t  \t\t\t\t\t\t'opacity': options.legend.backgroundOpacity\r\n\t  \t\t\t\t\t});\t\t\t\t\t\t\r\n\t  \t\t\t\t}\r\n\t  \t\t\t}\r\n\t  \t\t}\r\n\t    }\r\n    }\r\n\t},\r\n\t/**\r\n\t * Function: getEventPosition\r\n\t * \r\n\t * Calculates the coordinates from a mouse event object.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tevent - Mouse Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tObject with x and y coordinates of the mouse.\r\n\t */\r\n\tgetEventPosition: function (event){\r\n\t\tvar offset = this.overlay.cumulativeOffset(),\r\n\t\t\trx = (event.pageX - offset.left - this.plotOffset.left),\r\n\t\t\try = (event.pageY - offset.top - this.plotOffset.top),\r\n\t\t\tax = 0, ay = 0\r\n\t\t\t\r\n\t\tif(event.pageX == null && event.clientX != null){\r\n\t\t\tvar de = document.documentElement, b = document.body;\r\n\t\t\tax = event.clientX + (de && de.scrollLeft || b.scrollLeft || 0);\r\n\t\t\tay = event.clientY + (de && de.scrollTop || b.scrollTop || 0);\r\n\t\t}else{\r\n\t\t\tax = event.pageX;\r\n\t\t\tay = event.pageY;\r\n\t\t}\r\n\t\t\r\n\t\treturn {\r\n\t\t\tx:  this.axes.x.min  + rx / this.axes.x.scale,\r\n\t\t\tx2: this.axes.x2.min + rx / this.axes.x2.scale,\r\n\t\t\ty:  this.axes.y.max  - ry / this.axes.y.scale,\r\n\t\t\ty2: this.axes.y2.max - ry / this.axes.y2.scale,\r\n\t\t\trelX: rx,\r\n\t\t\trelY: ry,\r\n\t\t\tabsX: ax,\r\n\t\t\tabsY: ay\r\n\t\t};\r\n\t},\r\n\t/**\r\n\t * Function: clickHandler\r\n\t * \r\n\t * Handler observes the 'click' event and fires the 'flotr:click' event.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tevent - 'click' Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tclickHandler: function(event){\r\n\t\tif(this.ignoreClick){\r\n\t\t\tthis.ignoreClick = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.el.fire('flotr:click', [this.getEventPosition(event), this]);\r\n\t},\r\n\t/**\r\n\t * Function: mouseMoveHandler\r\n\t * \r\n\t * Handler observes mouse movement over the graph area. Fires the \r\n\t * 'flotr:mousemove' event.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tevent - 'mousemove' Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tmouseMoveHandler: function(event){\r\n \t\tvar pos = this.getEventPosition(event);\r\n    \r\n\t\tthis.lastMousePos.pageX = pos.absX;\r\n\t\tthis.lastMousePos.pageY = pos.absY;\t\r\n\t\tif(this.selectionInterval == null && (this.options.mouse.track || this.series.any(function(s){return s.mouse && s.mouse.track;}))){\t\r\n\t\t\tthis.hit(pos);\r\n\t\t}\r\n    \r\n\t\tthis.el.fire('flotr:mousemove', [event, pos, this]);\r\n\t},\r\n\t/**\r\n\t * Function: mouseDownHandler\r\n\t * \r\n\t * Handler observes the 'mousedown' event.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tevent - 'mousedown' Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tmouseDownHandler: function (event){\r\n    if(event.isRightClick()) {\r\n      event.stop();\r\n      var overlay = this.overlay;\r\n      overlay.hide();\r\n      \r\n      function cancelContextMenu () {\r\n        overlay.show();\r\n        $(document).stopObserving('mousemove', cancelContextMenu);\r\n      }\r\n      $(document).observe('mousemove', cancelContextMenu);\r\n      return;\r\n    }\r\n    \r\n\t\tif(!this.options.selection.mode || !event.isLeftClick()) return;\r\n\t\t\r\n\t\tthis.setSelectionPos(this.selection.first, event);\t\t\t\t\r\n\t\tif(this.selectionInterval != null){\r\n\t\t\tclearInterval(this.selectionInterval);\r\n\t\t}\r\n\t\tthis.lastMousePos.pageX = null;\r\n\t\tthis.selectionInterval = setInterval(this.updateSelection.bind(this), 1000/this.options.selection.fps);\r\n\t\t\r\n\t\tthis.mouseUpHandler = this.mouseUpHandler.bind(this);\r\n\t\t$(document).observe('mouseup', this.mouseUpHandler);\r\n\t},\r\n\t/**\r\n\t * Function: (private) fireSelectEvent\r\n\t * \r\n\t * Fires the 'flotr:select' event when the user made a selection.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tfireSelectEvent: function(){\r\n\t\tvar a = this.axes, selection = this.selection,\r\n\t\t\tx1 = (selection.first.x <= selection.second.x) ? selection.first.x : selection.second.x,\r\n\t\t\tx2 = (selection.first.x <= selection.second.x) ? selection.second.x : selection.first.x,\r\n\t\t\ty1 = (selection.first.y >= selection.second.y) ? selection.first.y : selection.second.y,\r\n\t\t\ty2 = (selection.first.y >= selection.second.y) ? selection.second.y : selection.first.y;\r\n\t\t\r\n\t\tx1 = a.x.min + x1 / a.x.scale;\r\n\t\tx2 = a.x.min + x2 / a.x.scale;\r\n\t\ty1 = a.y.max - y1 / a.y.scale;\r\n\t\ty2 = a.y.max - y2 / a.y.scale;\r\n\r\n\t\tthis.el.fire('flotr:select', [{x1:x1, y1:y1, x2:x2, y2:y2}, this]);\r\n\t},\r\n\t/**\r\n\t * Function: (private) mouseUpHandler\r\n\t * \r\n\t * Handler observes the mouseup event for the document. \r\n\t * \r\n\t * Parameters:\r\n\t * \t\tevent - 'mouseup' Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tmouseUpHandler: function(event){\r\n    $(document).stopObserving('mouseup', this.mouseUpHandler);\r\n    event.stop();\r\n    \r\n\t\tif(this.selectionInterval != null){\r\n\t\t\tclearInterval(this.selectionInterval);\r\n\t\t\tthis.selectionInterval = null;\r\n\t\t}\r\n\r\n\t\tthis.setSelectionPos(this.selection.second, event);\r\n\t\tthis.clearSelection();\r\n\t\t\r\n\t\tif(this.selectionIsSane()){\r\n\t\t\tthis.drawSelection();\r\n\t\t\tthis.fireSelectEvent();\r\n\t\t\tthis.ignoreClick = true;\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Function: setSelectionPos\r\n\t * \r\n\t * Calculates the position of the selection.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tpos - Position object.\r\n\t * \t\tevent - Event object.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tsetSelectionPos: function(pos, event) {\r\n\t\tvar options = this.options,\r\n\t\t    offset = $(this.overlay).cumulativeOffset();\r\n\t\t\r\n\t\tif(options.selection.mode.indexOf('x') == -1){\r\n\t\t\tpos.x = (pos == this.selection.first) ? 0 : this.plotWidth;\t\t\t   \r\n\t\t}else{\r\n\t\t\tpos.x = event.pageX - offset.left - this.plotOffset.left;\r\n\t\t\tpos.x = Math.min(Math.max(0, pos.x), this.plotWidth);\r\n\t\t}\r\n\r\n\t\tif (options.selection.mode.indexOf('y') == -1){\r\n\t\t\tpos.y = (pos == this.selection.first) ? 0 : this.plotHeight;\r\n\t\t}else{\r\n\t\t\tpos.y = event.pageY - offset.top - this.plotOffset.top;\r\n\t\t\tpos.y = Math.min(Math.max(0, pos.y), this.plotHeight);\r\n\t\t}\r\n\t},\r\n\t/**\r\n\t * Function: updateSelection\r\n\t * \r\n\t * Updates (draws) the selection box.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tupdateSelection: function(){\r\n\t\tif(this.lastMousePos.pageX == null) return;\r\n\t\t\r\n\t\tthis.setSelectionPos(this.selection.second, this.lastMousePos);\r\n\t\tthis.clearSelection();\r\n\t\t\r\n\t\tif(this.selectionIsSane()) this.drawSelection();\r\n\t},\r\n\t/**\r\n\t * Function: clearSelection\r\n\t * \r\n\t * Removes the selection box from the overlay canvas.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tclearSelection: function() {\r\n\t\tif(this.prevSelection == null) return;\r\n\t\t\t\r\n\t\tvar prevSelection = this.prevSelection,\r\n\t\t\toctx = this.octx,\r\n\t\t\tplotOffset = this.plotOffset,\r\n\t\t\tx = Math.min(prevSelection.first.x, prevSelection.second.x),\r\n\t\t\ty = Math.min(prevSelection.first.y, prevSelection.second.y),\r\n\t\t\tw = Math.abs(prevSelection.second.x - prevSelection.first.x),\r\n\t\t\th = Math.abs(prevSelection.second.y - prevSelection.first.y);\r\n\t\t\r\n\t\toctx.clearRect(x + plotOffset.left - octx.lineWidth,\r\n\t\t               y + plotOffset.top - octx.lineWidth,\r\n\t\t               w + octx.lineWidth*2,\r\n\t\t               h + octx.lineWidth*2);\r\n\t\t\r\n\t\tthis.prevSelection = null;\r\n\t},\r\n\t/**\r\n\t * Function: setSelection\r\n\t * \r\n\t * Allows the user the manually select an area.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tarea - Object with coordinates to select.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tsetSelection: function(area){\r\n\t\tvar options = this.options,\r\n\t\t\txa = this.axes.x,\r\n\t\t\tya = this.axes.y,\r\n\t\t\tvertScale = yaxis.scale,\r\n\t\t\thozScale = xaxis.scale,\r\n\t\t\tselX = options.selection.mode.indexOf('x') != -1,\r\n\t\t\tselY = options.selection.mode.indexOf('y') != -1;\r\n\t\t\r\n\t\tthis.clearSelection();\r\n\r\n\t\tthis.selection.first.y  = selX ? 0 : (ya.max - area.y1) * vertScale;\r\n\t\tthis.selection.second.y = selX ? this.plotHeight : (ya.max - area.y2) * vertScale;\t\t\t\r\n\t\tthis.selection.first.x  = selY ? 0 : (area.x1 - xa.min) * hozScale;\r\n\t\tthis.selection.second.x = selY ? this.plotWidth : (area.x2 - xa.min) * hozScale;\r\n\t\t\r\n\t\tthis.drawSelection();\r\n\t\tthis.fireSelectEvent();\r\n\t},\r\n\t/**\r\n\t * Function: (private) drawSelection\r\n\t * \r\n\t * Draws the selection box.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tdrawSelection: function() {\r\n\t\tvar prevSelection = this.prevSelection,\r\n\t\t\tselection = this.selection,\r\n\t\t\toctx = this.octx,\r\n\t\t\toptions = this.options,\r\n\t\t\tplotOffset = this.plotOffset;\r\n\t\t\r\n\t\tif(prevSelection != null &&\r\n\t\t\tselection.first.x == prevSelection.first.x &&\r\n\t\t\tselection.first.y == prevSelection.first.y && \r\n\t\t\tselection.second.x == prevSelection.second.x &&\r\n\t\t\tselection.second.y == prevSelection.second.y)\r\n\t\t\treturn;\r\n\t\t\r\n\t\toctx.strokeStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.8).toString();\r\n\t\toctx.lineWidth = 1;\r\n\t\toctx.lineJoin = 'round';\r\n\t\toctx.fillStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.4).toString();\r\n\r\n\t\tthis.prevSelection = {\r\n\t\t\tfirst: { x: selection.first.x, y: selection.first.y },\r\n\t\t\tsecond: { x: selection.second.x, y: selection.second.y }\r\n\t\t};\r\n\r\n\t\tvar x = Math.min(selection.first.x, selection.second.x),\r\n\t\t    y = Math.min(selection.first.y, selection.second.y),\r\n\t\t    w = Math.abs(selection.second.x - selection.first.x),\r\n\t\t    h = Math.abs(selection.second.y - selection.first.y);\r\n\t\t\r\n\t\toctx.fillRect(x + plotOffset.left, y + plotOffset.top, w, h);\r\n\t\toctx.strokeRect(x + plotOffset.left, y + plotOffset.top, w, h);\r\n\t},\r\n\t/**\r\n\t * Function: (private) selectionIsSane\r\n\t * \r\n\t * Determines whether or not the selection is sane and should be drawn.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tboolean - True when sane, false otherwise.\r\n\t */\r\n\tselectionIsSane: function(){\r\n\t\tvar selection = this.selection;\r\n\t\treturn Math.abs(selection.second.x - selection.first.x) >= 5 &&\r\n\t\t       Math.abs(selection.second.y - selection.first.y) >= 5;\r\n\t},\r\n\t/**\r\n\t * Function: clearHit\r\n\t * \r\n\t * Removes the mouse tracking point from the overlay.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tnone\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\tclearHit: function(){\r\n\t\tif(this.prevHit){\r\n\t\t\tvar options = this.options,\r\n\t\t\t    plotOffset = this.plotOffset,\r\n\t\t\t    prevHit = this.prevHit;\r\n\t\t\t\t\t\r\n\t\t\tthis.octx.clearRect(\r\n\t\t\t\tthis.tHoz(prevHit.x) + plotOffset.left - options.points.radius*2,\r\n\t\t\t\tthis.tVert(prevHit.y) + plotOffset.top - options.points.radius*2,\r\n\t\t\t\toptions.points.radius*3 + options.points.lineWidth*3, \r\n\t\t\t\toptions.points.radius*3 + options.points.lineWidth*3\r\n\t\t\t);\r\n\t\t\tthis.prevHit = null;\r\n\t\t}\t\t\r\n\t},\r\n\t/**\r\n\t * Function: hit\r\n\t * \r\n\t * Retrieves the nearest data point from the mouse cursor. If it's within\r\n\t * a certain range, draw a point on the overlay canvas and display the x and y\r\n\t * value of the data.\r\n\t * \r\n\t * Parameters:\r\n\t * \t\tmouse - Object that holds the relative x and y coordinates of the cursor.\r\n\t * \r\n\t * Returns:\r\n\t * \t\tvoid\r\n\t */\r\n\thit: function(mouse){\r\n\t\tvar series = this.series,\r\n\t\t\toptions = this.options,\r\n\t\t\tprevHit = this.prevHit,\r\n\t\t\tplotOffset = this.plotOffset,\r\n\t\t\toctx = this.octx, \r\n\t\t\tdata, xsens, ysens,\r\n\t\t\t/**\r\n\t\t\t * Nearest data element.\r\n\t\t\t */\r\n\t\t\ti, n = {\r\n\t\t\t\tdist:Number.MAX_VALUE,\r\n\t\t\t\tx:null,\r\n\t\t\t\ty:null,\r\n\t\t\t\trelX:mouse.relX,\r\n\t\t\t\trelY:mouse.relY,\r\n\t\t\t\tabsX:mouse.absX,\r\n\t\t\t\tabsY:mouse.absY,\r\n\t\t\t\tmouse:null\r\n\t\t\t};\r\n\t\t\r\n\t\tfor(i = 0; i < series.length; i++){\r\n\t\t\ts = series[i];\r\n\t\t\tif(!s.mouse.track) continue;\r\n\t\t\tdata = s.data;\r\n\t\t\txsens = (s.xaxis.scale*s.mouse.sensibility);\r\n\t\t\tysens = (s.yaxis.scale*s.mouse.sensibility);\r\n\r\n\t\t\tfor(var j = 0, xpow, ypow; j < data.length; j++){\r\n\t\t\t\tif (data[j][1] === null) continue;\r\n\t\t\t\txpow = Math.pow(s.xaxis.scale*(data[j][0] - mouse.x), 2);\r\n\t\t\t\typow = Math.pow(s.yaxis.scale*(data[j][1] - mouse.y), 2);\r\n\t\t\t\tif(xpow < xsens && ypow < ysens && Math.sqrt(xpow+ypow) < n.dist){\r\n\t\t\t\t\tn.dist = Math.sqrt(xpow+ypow);\r\n\t\t\t\t\tn.x = data[j][0];\r\n\t\t\t\t\tn.y = data[j][1];\r\n\t\t\t\t\tn.mouse = s.mouse;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tif(n.mouse && n.mouse.track && !prevHit || (prevHit && (n.x != prevHit.x || n.y != prevHit.y))){\r\n\t\t\tvar mt = this.mouseTrack || this.el.select(\".flotr-mouse-value\")[0],\r\n\t\t\t    pos = '', \r\n\t\t\t    p = options.mouse.position, \r\n\t\t\t    m = options.mouse.margin,\r\n\t\t\t    elStyle = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;';\r\n\r\n\t\t\tif (!options.mouse.relative) { // absolute to the canvas\r\n\t\t\t\t\t\t if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';\r\n\t\t\t\telse if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';\t\t\t\t\t\r\n\t\t\t\t     if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';\r\n\t\t\t\telse if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';\r\n\t\t\t}\r\n\t\t\telse { // relative to the mouse\r\n\t\t\t       if(p.charAt(0) == 'n') pos += 'bottom:' + (m - plotOffset.top - this.tVert(n.y) + this.canvasHeight) + 'px;';\r\n\t\t\t\telse if(p.charAt(0) == 's') pos += 'top:' + (m + plotOffset.top + this.tVert(n.y)) + 'px;';\r\n\t\t\t\t     if(p.charAt(1) == 'e') pos += 'left:' + (m + plotOffset.left + this.tHoz(n.x)) + 'px;';\r\n\t\t\t\telse if(p.charAt(1) == 'w') pos += 'right:' + (m - plotOffset.left - this.tHoz(n.x) + this.canvasWidth) + 'px;';\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\telStyle += pos;\r\n\t\t\t\t     \r\n\t\t\tif(!mt){\r\n\t\t\t\tthis.el.insert('<div class=\"flotr-mouse-value\" style=\"'+elStyle+'\"></div>');\r\n\t\t\t\tmt = this.mouseTrack = this.el.select('.flotr-mouse-value').first();\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tthis.mouseTrack = mt.setStyle(elStyle);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif(n.x !== null && n.y !== null){\r\n\t\t\t\tmt.show();\r\n\t\t\t\t\r\n\t\t\t\tthis.clearHit();\r\n\t\t\t\tif(n.mouse.lineColor != null){\r\n\t\t\t\t\toctx.save();\r\n\t\t\t\t\toctx.translate(plotOffset.left, plotOffset.top);\r\n\t\t\t\t\toctx.lineWidth = options.points.lineWidth;\r\n\t\t\t\t\toctx.strokeStyle = n.mouse.lineColor;\r\n\t\t\t\t\toctx.fillStyle = '#ffffff';\r\n\t\t\t\t\toctx.beginPath();\r\n\t\t\t\t\toctx.arc(this.tHoz(n.x), this.tVert(n.y), options.mouse.radius, 0, 2 * Math.PI, true);\r\n\t\t\t\t\toctx.fill();\r\n\t\t\t\t\toctx.stroke();\r\n\t\t\t\t\toctx.restore();\r\n\t\t\t\t}\r\n\t\t\t\tthis.prevHit = n;\r\n\t\t\t\t\r\n\t\t\t\tvar decimals = n.mouse.trackDecimals;\r\n\t\t\t\tif(decimals == null || decimals < 0) decimals = 0;\r\n\t\t\t\t\r\n\t\t\t\tmt.innerHTML = n.mouse.trackFormatter({x: n.x.toFixed(decimals), y: n.y.toFixed(decimals)});\r\n\t\t\t\tmt.fire('flotr:hit', [n, this]);\r\n\t\t\t}\r\n\t\t\telse if(prevHit){\r\n\t\t\t\tmt.hide();\r\n\t\t\t\tthis.clearHit();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\tsaveImage: function (type, width, height, replaceCanvas) {\r\n\t\tvar image = null;\r\n\t  switch (type) {\r\n\t  \tcase 'jpeg':\r\n\t    case 'jpg': image = Canvas2Image.saveAsJPEG(this.canvas, replaceCanvas, width, height); break;\r\n      default:\r\n      case 'png': image = Canvas2Image.saveAsPNG(this.canvas, replaceCanvas, width, height); break;\r\n      case 'bmp': image = Canvas2Image.saveAsBMP(this.canvas, replaceCanvas, width, height); break;\r\n\t  }\r\n\t  if (Object.isElement(image) && replaceCanvas) {\r\n\t    this.restoreCanvas();\r\n\t    this.canvas.hide();\r\n\t    this.overlay.hide();\r\n\t  \tthis.el.insert(image.setStyle({position: 'absolute'}));\r\n\t  }\r\n\t},\r\n\trestoreCanvas: function() {\r\n    this.canvas.show();\r\n    this.overlay.show();\r\n    this.el.select('img').invoke('remove');\r\n\t}\r\n});\r\n\r\nFlotr.Color = Class.create({\r\n\tinitialize: function(r, g, b, a){\r\n\t\tthis.rgba = ['r','g','b','a'];\r\n\t\tvar x = 4;\r\n\t\twhile(-1<--x){\r\n\t\t\tthis[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);\r\n\t\t}\r\n\t\tthis.normalize();\r\n\t},\r\n\t\r\n\tadjust: function(rd, gd, bd, ad) {\r\n\t\tvar x = 4;\r\n\t\twhile(-1<--x){\r\n\t\t\tif(arguments[x] != null)\r\n\t\t\t\tthis[this.rgba[x]] += arguments[x];\r\n\t\t}\r\n\t\treturn this.normalize();\r\n\t},\r\n\t\r\n\tclone: function(){\r\n\t\treturn new Flotr.Color(this.r, this.b, this.g, this.a);\r\n\t},\r\n\t\r\n\tlimit: function(val,minVal,maxVal){\r\n\t\treturn Math.max(Math.min(val, maxVal), minVal);\r\n\t},\r\n\t\r\n\tnormalize: function(){\r\n\t\tvar limit = this.limit;\r\n\t\tthis.r = limit(parseInt(this.r), 0, 255);\r\n\t\tthis.g = limit(parseInt(this.g), 0, 255);\r\n\t\tthis.b = limit(parseInt(this.b), 0, 255);\r\n\t\tthis.a = limit(this.a, 0, 1);\r\n\t\treturn this;\r\n\t},\r\n\t\r\n\tscale: function(rf, gf, bf, af){\r\n\t\tvar x = 4;\r\n\t\twhile(-1<--x){\r\n\t\t\tif(arguments[x] != null)\r\n\t\t\t\tthis[this.rgba[x]] *= arguments[x];\r\n\t\t}\r\n\t\treturn this.normalize();\r\n\t},\r\n\t\r\n\tdistance: function(color){\r\n\t\tif (!color) return;\r\n\t\tcolor = new Flotr.parseColor(color);\r\n\t  var dist = 0;\r\n\t\tvar x = 3;\r\n\t\twhile(-1<--x){\r\n\t\t\tdist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);\r\n\t\t}\r\n\t\treturn dist;\r\n\t},\r\n\t\r\n\ttoString: function(){\r\n\t\treturn (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')';\r\n\t}\r\n});\r\n\r\nFlotr.Color.lookupColors = {\r\n\taqua:[0,255,255],\r\n\tazure:[240,255,255],\r\n\tbeige:[245,245,220],\r\n\tblack:[0,0,0],\r\n\tblue:[0,0,255],\r\n\tbrown:[165,42,42],\r\n\tcyan:[0,255,255],\r\n\tdarkblue:[0,0,139],\r\n\tdarkcyan:[0,139,139],\r\n\tdarkgrey:[169,169,169],\r\n\tdarkgreen:[0,100,0],\r\n\tdarkkhaki:[189,183,107],\r\n\tdarkmagenta:[139,0,139],\r\n\tdarkolivegreen:[85,107,47],\r\n\tdarkorange:[255,140,0],\r\n\tdarkorchid:[153,50,204],\r\n\tdarkred:[139,0,0],\r\n\tdarksalmon:[233,150,122],\r\n\tdarkviolet:[148,0,211],\r\n\tfuchsia:[255,0,255],\r\n\tgold:[255,215,0],\r\n\tgreen:[0,128,0],\r\n\tindigo:[75,0,130],\r\n\tkhaki:[240,230,140],\r\n\tlightblue:[173,216,230],\r\n\tlightcyan:[224,255,255],\r\n\tlightgreen:[144,238,144],\r\n\tlightgrey:[211,211,211],\r\n\tlightpink:[255,182,193],\r\n\tlightyellow:[255,255,224],\r\n\tlime:[0,255,0],\r\n\tmagenta:[255,0,255],\r\n\tmaroon:[128,0,0],\r\n\tnavy:[0,0,128],\r\n\tolive:[128,128,0],\r\n\torange:[255,165,0],\r\n\tpink:[255,192,203],\r\n\tpurple:[128,0,128],\r\n\tviolet:[128,0,128],\r\n\tred:[255,0,0],\r\n\tsilver:[192,192,192],\r\n\twhite:[255,255,255],\r\n\tyellow:[255,255,0]\r\n};\r\n\r\n// not used yet\r\nFlotr.Date = {\r\n  format: function(d, format) {\r\n\t\tif (!d) return;\r\n\r\n    var leftPad = function(n) {\r\n      n = n.toString();\r\n      return n.length == 1 ? \"0\" + n : n;\r\n    };\r\n    \r\n    var r = [];\r\n    var escape = false;\r\n    \r\n    for (var i = 0; i < format.length; ++i) {\r\n      var c = format.charAt(i);\r\n      \r\n      if (escape) {\r\n        switch (c) {\r\n\t        case 'h': c = d.getUTCHours().toString(); break;\r\n\t        case 'H': c = leftPad(d.getUTCHours()); break;\r\n\t        case 'M': c = leftPad(d.getUTCMinutes()); break;\r\n\t        case 'S': c = leftPad(d.getUTCSeconds()); break;\r\n\t        case 'd': c = d.getUTCDate().toString(); break;\r\n\t        case 'm': c = (d.getUTCMonth() + 1).toString(); break;\r\n\t        case 'y': c = d.getUTCFullYear().toString(); break;\r\n\t        case 'b': c = Flotr.Date.monthNames[d.getUTCMonth()]; break;\r\n        }\r\n        r.push(c);\r\n        escape = false;\r\n      }\r\n      else {\r\n        if (c == \"%\")\r\n          escape = true;\r\n        else\r\n          r.push(c);\r\n      }\r\n    }\r\n    return r.join(\"\");\r\n  },\r\n  timeUnits: {\r\n    \"second\": 1000,\r\n    \"minute\": 60 * 1000,\r\n    \"hour\": 60 * 60 * 1000,\r\n    \"day\": 24 * 60 * 60 * 1000,\r\n    \"month\": 30 * 24 * 60 * 60 * 1000,\r\n    \"year\": 365.2425 * 24 * 60 * 60 * 1000\r\n  },\r\n  // the allowed tick sizes, after 1 year we use an integer algorithm\r\n  spec: [\r\n    [1, \"second\"], [2, \"second\"], [5, \"second\"], [10, \"second\"], [30, \"second\"], \r\n    [1, \"minute\"], [2, \"minute\"], [5, \"minute\"], [10, \"minute\"], [30, \"minute\"], \r\n    [1, \"hour\"], [2, \"hour\"], [4, \"hour\"], [8, \"hour\"], [12, \"hour\"],\r\n    [1, \"day\"], [2, \"day\"], [3, \"day\"],\r\n    [0.25, \"month\"], [0.5, \"month\"], [1, \"month\"], [2, \"month\"], [3, \"month\"], [6, \"month\"],\r\n    [1, \"year\"]\r\n  ],\r\n  monthNames: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\r\n};\r\n"
  },
  {
    "path": "input-scripts/flotr/lib/base64.js",
    "content": "/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>\r\n * Version: 1.0\r\n * LastModified: Dec 25 1999\r\n * This library is free.  You can redistribute it and/or modify it.\r\n */\r\n\r\n/*\r\n * Interfaces:\r\n * b64 = base64encode(data);\r\n * data = base64decode(b64);\r\n */\r\n\r\n(function() {\r\n\r\nvar base64EncodeChars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\r\nvar base64DecodeChars = [\r\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,\r\n    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,\r\n    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\r\n    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,\r\n    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,\r\n    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1];\r\n\r\nfunction base64encode(str) {\r\n    var out, i, len;\r\n    var c1, c2, c3;\r\n\r\n    len = str.length;\r\n    i = 0;\r\n    out = \"\";\r\n    while(i < len) {\r\n\tc1 = str.charCodeAt(i++) & 0xff;\r\n\tif(i == len)\r\n\t{\r\n\t    out += base64EncodeChars.charAt(c1 >> 2);\r\n\t    out += base64EncodeChars.charAt((c1 & 0x3) << 4);\r\n\t    out += \"==\";\r\n\t    break;\r\n\t}\r\n\tc2 = str.charCodeAt(i++);\r\n\tif(i == len)\r\n\t{\r\n\t    out += base64EncodeChars.charAt(c1 >> 2);\r\n\t    out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));\r\n\t    out += base64EncodeChars.charAt((c2 & 0xF) << 2);\r\n\t    out += \"=\";\r\n\t    break;\r\n\t}\r\n\tc3 = str.charCodeAt(i++);\r\n\tout += base64EncodeChars.charAt(c1 >> 2);\r\n\tout += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));\r\n\tout += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));\r\n\tout += base64EncodeChars.charAt(c3 & 0x3F);\r\n    }\r\n    return out;\r\n}\r\n\r\nfunction base64decode(str) {\r\n    var c1, c2, c3, c4;\r\n    var i, len, out;\r\n\r\n    len = str.length;\r\n    i = 0;\r\n    out = \"\";\r\n    while(i < len) {\r\n\t/* c1 */\r\n\tdo {\r\n\t    c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];\r\n\t} while(i < len && c1 == -1);\r\n\tif(c1 == -1)\r\n\t    break;\r\n\r\n\t/* c2 */\r\n\tdo {\r\n\t    c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];\r\n\t} while(i < len && c2 == -1);\r\n\tif(c2 == -1)\r\n\t    break;\r\n\r\n\tout += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));\r\n\r\n\t/* c3 */\r\n\tdo {\r\n\t    c3 = str.charCodeAt(i++) & 0xff;\r\n\t    if(c3 == 61)\r\n\t\treturn out;\r\n\t    c3 = base64DecodeChars[c3];\r\n\t} while(i < len && c3 == -1);\r\n\tif(c3 == -1)\r\n\t    break;\r\n\r\n\tout += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));\r\n\r\n\t/* c4 */\r\n\tdo {\r\n\t    c4 = str.charCodeAt(i++) & 0xff;\r\n\t    if(c4 == 61)\r\n\t\treturn out;\r\n\t    c4 = base64DecodeChars[c4];\r\n\t} while(i < len && c4 == -1);\r\n\tif(c4 == -1)\r\n\t    break;\r\n\tout += String.fromCharCode(((c3 & 0x03) << 6) | c4);\r\n    }\r\n    return out;\r\n}\r\n\r\nif (!window.btoa) window.btoa = base64encode;\r\nif (!window.atob) window.atob = base64decode;\r\n\r\n})();"
  },
  {
    "path": "input-scripts/flotr/lib/canvas2image.js",
    "content": "/*\r\n * Canvas2Image v0.1\r\n * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com\r\n * MIT License [http://www.opensource.org/licenses/mit-license.php]\r\n */\r\n\r\nvar Canvas2Image = (function() {\r\n\t// check if we have canvas support\r\n\tvar oCanvas = document.createElement(\"canvas\");\r\n  \r\n\t// no canvas, bail out.\r\n\tif (!oCanvas.getContext) {\r\n\t\treturn {\r\n\t\t\tsaveAsBMP : function(){},\r\n\t\t\tsaveAsPNG : function(){},\r\n\t\t\tsaveAsJPEG : function(){}\r\n\t\t}\r\n\t}\r\n\r\n\tvar bHasImageData = !!(oCanvas.getContext(\"2d\").getImageData);\r\n\tvar bHasDataURL = !!(oCanvas.toDataURL);\r\n\tvar bHasBase64 = !!(window.btoa);\r\n\r\n\tvar strDownloadMime = \"image/octet-stream\";\r\n\r\n\t// ok, we're good\r\n\tvar readCanvasData = function(oCanvas) {\r\n\t\tvar iWidth = parseInt(oCanvas.width);\r\n\t\tvar iHeight = parseInt(oCanvas.height);\r\n\t\treturn oCanvas.getContext(\"2d\").getImageData(0,0,iWidth,iHeight);\r\n\t}\r\n\r\n\t// base64 encodes either a string or an array of charcodes\r\n\tvar encodeData = function(data) {\r\n\t\tvar strData = \"\";\r\n\t\tif (typeof data == \"string\") {\r\n\t\t\tstrData = data;\r\n\t\t} else {\r\n\t\t\tvar aData = data;\r\n\t\t\tfor (var i = 0; i < aData.length; i++) {\r\n\t\t\t\tstrData += String.fromCharCode(aData[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn btoa(strData);\r\n\t}\r\n\r\n\t// creates a base64 encoded string containing BMP data\r\n\t// takes an imagedata object as argument\r\n\tvar createBMP = function(oData) {\r\n\t\tvar aHeader = [];\r\n\t\r\n\t\tvar iWidth = oData.width;\r\n\t\tvar iHeight = oData.height;\r\n\r\n\t\taHeader.push(0x42); // magic 1\r\n\t\taHeader.push(0x4D); \r\n\t\r\n\t\tvar iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes\r\n\t\taHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);\r\n\t\taHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);\r\n\t\taHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);\r\n\t\taHeader.push(iFileSize % 256);\r\n\r\n\t\taHeader.push(0); // reserved\r\n\t\taHeader.push(0);\r\n\t\taHeader.push(0); // reserved\r\n\t\taHeader.push(0);\r\n\r\n\t\taHeader.push(54); // data offset\r\n\t\taHeader.push(0);\r\n\t\taHeader.push(0);\r\n\t\taHeader.push(0);\r\n\r\n\t\tvar aInfoHeader = [];\r\n\t\taInfoHeader.push(40); // info header size\r\n\t\taInfoHeader.push(0);\r\n\t\taInfoHeader.push(0);\r\n\t\taInfoHeader.push(0);\r\n\r\n\t\tvar iImageWidth = iWidth;\r\n\t\taInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);\r\n\t\taInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);\r\n\t\taInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);\r\n\t\taInfoHeader.push(iImageWidth % 256);\r\n\t\r\n\t\tvar iImageHeight = iHeight;\r\n\t\taInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);\r\n\t\taInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);\r\n\t\taInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);\r\n\t\taInfoHeader.push(iImageHeight % 256);\r\n\t\r\n\t\taInfoHeader.push(1); // num of planes\r\n\t\taInfoHeader.push(0);\r\n\t\r\n\t\taInfoHeader.push(24); // num of bits per pixel\r\n\t\taInfoHeader.push(0);\r\n\t\r\n\t\taInfoHeader.push(0); // compression = none\r\n\t\taInfoHeader.push(0);\r\n\t\taInfoHeader.push(0);\r\n\t\taInfoHeader.push(0);\r\n\t\r\n\t\tvar iDataSize = iWidth*iHeight*3; \r\n\t\taInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);\r\n\t\taInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);\r\n\t\taInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);\r\n\t\taInfoHeader.push(iDataSize % 256); \r\n\t\r\n\t\tfor (var i = 0; i < 16; i++) {\r\n\t\t\taInfoHeader.push(0);\t// these bytes not used\r\n\t\t}\r\n\t\r\n\t\tvar iPadding = (4 - ((iWidth * 3) % 4)) % 4;\r\n\r\n\t\tvar aImgData = oData.data;\r\n\r\n\t\tvar strPixelData = \"\";\r\n\t\tvar y = iHeight;\r\n\t\tdo {\r\n\t\t\tvar iOffsetY = iWidth*(y-1)*4;\r\n\t\t\tvar strPixelRow = \"\";\r\n\t\t\tfor (var x=0;x<iWidth;x++) {\r\n\t\t\t\tvar iOffsetX = 4*x;\r\n\r\n\t\t\t\tstrPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);\r\n\t\t\t\tstrPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);\r\n\t\t\t\tstrPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);\r\n\t\t\t}\r\n\t\t\tfor (var c=0;c<iPadding;c++) {\r\n\t\t\t\tstrPixelRow += String.fromCharCode(0);\r\n\t\t\t}\r\n\t\t\tstrPixelData += strPixelRow;\r\n\t\t} while (--y);\r\n\r\n\t\treturn encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);\r\n\t}\r\n\r\n\t// sends the generated file to the client\r\n\tvar saveFile = function(strData) {\r\n    if (!window.open(strData)) {\r\n      document.location.href = strData;\r\n    }\r\n\t}\r\n\r\n\tvar makeDataURI = function(strData, strMime) {\r\n\t\treturn \"data:\" + strMime + \";base64,\" + strData;\r\n\t}\r\n\r\n\t// generates a <img> object containing the imagedata\r\n\tvar makeImageObject = function(strSource) {\r\n\t\tvar oImgElement = document.createElement(\"img\");\r\n\t\toImgElement.src = strSource;\r\n\t\treturn oImgElement;\r\n\t}\r\n\r\n\tvar scaleCanvas = function(oCanvas, iWidth, iHeight) {\r\n\t\tif (iWidth && iHeight) {\r\n\t\t\tvar oSaveCanvas = document.createElement(\"canvas\");\r\n\t\t\t\r\n\t\t\toSaveCanvas.width = iWidth;\r\n\t\t\toSaveCanvas.height = iHeight;\r\n\t\t\toSaveCanvas.style.width = iWidth+\"px\";\r\n\t\t\toSaveCanvas.style.height = iHeight+\"px\";\r\n\r\n\t\t\tvar oSaveCtx = oSaveCanvas.getContext(\"2d\");\r\n\r\n\t\t\toSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);\r\n\t\t\t\r\n\t\t\treturn oSaveCanvas;\r\n\t\t}\r\n\t\treturn oCanvas;\r\n\t}\r\n\r\n\treturn {\r\n\t\tsaveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {\r\n\t\t\tif (!bHasDataURL) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tvar oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);\r\n\t\t\tvar strData = oScaledCanvas.toDataURL(\"image/png\");\r\n\t\t\tif (bReturnImg) {\r\n\t\t\t\treturn makeImageObject(strData);\r\n\t\t\t} else {\r\n\t\t\t\tsaveFile(strData.replace(\"image/png\", strDownloadMime));\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\r\n\t\tsaveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {\r\n\t\t\tif (!bHasDataURL) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tvar oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);\r\n\t\t\tvar strMime = \"image/jpeg\";\r\n\t\t\tvar strData = oScaledCanvas.toDataURL(strMime);\r\n\t\r\n\t\t\t// check if browser actually supports jpeg by looking for the mime type in the data uri.\r\n\t\t\t// if not, return false\r\n\t\t\tif (strData.indexOf(strMime) != 5) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tif (bReturnImg) {\r\n\t\t\t\treturn makeImageObject(strData);\r\n\t\t\t} else {\r\n\t\t\t\tsaveFile(strData.replace(strMime, strDownloadMime));\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\r\n\t\tsaveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {\r\n\t\t\tif (!(bHasImageData && bHasBase64)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tvar oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);\r\n\r\n\t\t\tvar oData = readCanvasData(oScaledCanvas);\r\n\t\t\tvar strImgData = createBMP(oData);\r\n\t\t\tif (bReturnImg) {\r\n\t\t\t\treturn makeImageObject(makeDataURI(strImgData, \"image/bmp\"));\r\n\t\t\t} else {\r\n\t\t\t\tsaveFile(makeDataURI(strImgData, strDownloadMime));\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t};\r\n\r\n})();"
  },
  {
    "path": "input-scripts/flotr/lib/canvastext.js",
    "content": "/**\r\n * This code is released to the public domain by Jim Studt, 2007.\r\n * He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/\r\n * It as been modified by Fabien Mnager to handle font style like size, weight, color and rotation. \r\n * A partial support for accentuated letters as been added too.\r\n */\r\nvar CanvasText = {\r\n\t/** The letters definition. It is a list of letters, \r\n\t * with their width, and the coordinates of points compositing them.\r\n\t * The syntax for the points is : [x, y], null value means \"pen up\"\r\n\t */\r\n  letters: {\r\n\t\t'\\n':{ width: -1, points: [] },\r\n    ' ': { width: 10, points: [] },\r\n    '!': { width: 10, points: [[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },\r\n    '\"': { width: 16, points: [[4,21],[4,14],null,[12,21],[12,14]] },\r\n    '#': { width: 21, points: [[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]] },\r\n    '$': { width: 20, points: [[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },\r\n    '%': { width: 24, points: [[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },\r\n    '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },\r\n    '\\'':{ width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },\r\n    '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },\r\n    ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },\r\n    '*': { width: 16, points: [[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]] },\r\n    '+': { width: 26, points: [[13,18],[13,0],null,[4,9],[22,9]] },\r\n    ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },\r\n    '-': { width: 26, points: [[4,9],[22,9]] },\r\n    '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },\r\n    '/': { width: 22, points: [[20,25],[2,-7]] },\r\n    '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },\r\n    '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },\r\n    '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },\r\n    '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },\r\n    '4': { width: 20, points: [[13,21],[3,7],[18,7],null,[13,21],[13,0]] },\r\n    '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },\r\n    '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },\r\n    '7': { width: 20, points: [[17,21],[7,0],null,[3,21],[17,21]] },\r\n    '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },\r\n    '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },\r\n    ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },\r\n    ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },\r\n    '<': { width: 24, points: [[20,18],[4,9],[20,0]] },\r\n    '=': { width: 26, points: [[4,12],[22,12],null,[4,6],[22,6]] },\r\n    '>': { width: 24, points: [[4,18],[20,9],[4,0]] },\r\n    '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]] },\r\n    '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]] },\r\n    'A': { width: 18, points: [[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]] },\r\n    'B': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },\r\n    'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },\r\n    'D': { width: 21, points: [[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },\r\n    'E': { width: 19, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]] },\r\n    'F': { width: 18, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]] },\r\n    'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]] },\r\n    'H': { width: 22, points: [[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]] },\r\n    'I': { width: 8,  points: [[4,21],[4,0]] },\r\n    'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },\r\n    'K': { width: 21, points: [[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]] },\r\n    'L': { width: 17, points: [[4,21],[4,0],null,[4,0],[16,0]] },\r\n    'M': { width: 24, points: [[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]] },\r\n    'N': { width: 22, points: [[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]] },\r\n    'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },\r\n    'P': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },\r\n    'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]] },\r\n    'R': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]] },\r\n    'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },\r\n    'T': { width: 16, points: [[8,21],[8,0],null,[1,21],[15,21]] },\r\n    'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },\r\n    'V': { width: 18, points: [[1,21],[9,0],null,[17,21],[9,0]] },\r\n    'W': { width: 24, points: [[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]] },\r\n    'X': { width: 20, points: [[3,21],[17,0],null,[17,21],[3,0]] },\r\n    'Y': { width: 18, points: [[1,21],[9,11],[9,0],null,[17,21],[9,11]] },\r\n    'Z': { width: 20, points: [[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]] },\r\n    '[': { width: 14, points: [[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]] },\r\n    '\\\\':{ width: 14, points: [[0,21],[14,-3]] },\r\n    ']': { width: 14, points: [[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]] },\r\n    '^': { width: 14, points: [[3,10],[8,18],[13,10]] },\r\n    '_': { width: 16, points: [[0,-2],[16,-2]] },\r\n    '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },\r\n    'a': { width: 19, points: [[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'b': { width: 19, points: [[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },\r\n    'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'd': { width: 19, points: [[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]] },\r\n    'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'h': { width: 19, points: [[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },\r\n    'i': { width: 8,  points: [[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]] },\r\n    'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },\r\n    'k': { width: 17, points: [[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]] },\r\n    'l': { width: 8,  points: [[4,21],[4,0]] },\r\n    'm': { width: 30, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },\r\n    'n': { width: 19, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },\r\n    'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },\r\n    'p': { width: 19, points: [[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },\r\n    'q': { width: 19, points: [[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },\r\n    'r': { width: 13, points: [[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]] },\r\n    's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },\r\n    't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]] },\r\n    'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]] },\r\n    'v': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0]] },\r\n    'w': { width: 22, points: [[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]] },\r\n    'x': { width: 17, points: [[3,14],[14,0],null,[14,14],[3,0]] },\r\n    'y': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },\r\n    'z': { width: 17, points: [[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]] },\r\n    '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },\r\n    '|': { width: 8,  points: [[4,25],[4,-7]] },\r\n    '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },\r\n    '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] },\r\n    '': { diacritic: '', letter: 'e' },\r\n    '': { diacritic: '`', letter: 'e' },\r\n    '': { diacritic: '^', letter: 'e' },\r\n    '': { diacritic: '', letter: 'e' },\r\n    '': { diacritic: '`', letter: 'a' },\r\n    '': { diacritic: '', letter: 'c' },\r\n    '': { diacritic: '~', letter: 'n' },\r\n    '': { diacritic: '^', letter: 'o' },\r\n    '': { diacritic: '', letter: 'E' },\r\n    '': { diacritic: '`', letter: 'E' },\r\n    '': { diacritic: '^', letter: 'E' },\r\n    '': { diacritic: '', letter: 'E' },\r\n    '': { diacritic: '`', letter: 'A' },\r\n    '': { diacritic: '', letter: 'C' },\r\n    '': { diacritic: '~', letter: 'N' },\r\n    '': { diacritic: '^', letter: 'O' }\r\n  },\r\n  \r\n  specialchars: {\r\n  \t'pi': { width: 19, points: [[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]] }\r\n  },\r\n  \r\n  /** Diacritics, used to draw accentuated letters */\r\n  diacritics: {\r\n    '': { entity: 'cedil', points: [[6,-4],[4,-6],[2,-7],[1,-7]] },\r\n    '': { entity: 'acute', points: [[8,19],[13,22]] },\r\n    '`': { entity: 'grave', points: [[7,22],[12,19]] },\r\n    '^': { entity: 'circ',  points: [[5.5,19],[9.5,23],[12.5,19]] },\r\n    '': { entity: 'trema', points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[12,21],[13,20],[14,21],[13,22],[12,21]] },\r\n    '~': { entity: 'tilde', points: [[4,18],[7,22],[10,18],[13,22]] }\r\n  },\r\n  \r\n  /** The default font styling */\r\n  style: {\r\n    size: 8,          // font height in pixels\r\n    font: null,       // not yet implemented\r\n    color: '#000000', // \r\n    weight: 1,        // float, 1 for 'normal'\r\n    halign: 'l',      // l: left, r: right, c: center\r\n    valign: 'b',      // t: top, m: middle, b: bottom \r\n    adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position\r\n    angle: 0,         // in radians, anticlockwise\r\n    tracking: 1,      // space between the letters, float, 1 for 'normal'\r\n    boundingBoxColor: '#ff0000', //null // color of the bounding box (null to hide), can be used for debug and font drawing\r\n    originPointColor: '#000000' //null // color of the bounding box (null to hide), can be used for debug and font drawing\r\n  },\r\n  \r\n  debug: false,\r\n  _bufferLexemes: {},\r\n  \r\n  /** Get the letter data corresponding to a char\r\n   * @param {String} ch - The char\r\n   */\r\n  letter: function(ch) {\r\n    return CanvasText.letters[ch];\r\n  },\r\n  \r\n  parseLexemes: function(str) {\r\n    if (CanvasText._bufferLexemes[str]) \r\n      return CanvasText._bufferLexemes[str];\r\n    \r\n  \tvar i, c, matches = str.match(/&[A-Za-z]{2,5};|\\s|./g);\r\n  \tvar result = [], chars = [];\r\n  \tfor (i = 0; i < matches.length; i++) {\r\n  \t\tc = matches[i];\r\n  \t\tif (c.length == 1) \r\n  \t\t\tchars.push(c);\r\n  \t\telse {\r\n  \t\t\tvar entity = c.substring(1, c.length-1);\r\n  \t\t\tif (CanvasText.specialchars[entity]) \r\n  \t\t\t\tchars.push(entity);\r\n  \t\t\telse\r\n  \t\t\t\tchars = chars.concat(c.toArray());\r\n  \t\t}\r\n  \t}\r\n  \tfor (i = 0; i < chars.length; i++) {\r\n  \t\tc = chars[i];\r\n  \t\tif (c = CanvasText.letters[c] || CanvasText.specialchars[c])\r\n  \t\t  result.push(c);\r\n  \t}\r\n  \treturn CanvasText._bufferLexemes[str] = result.compact();\r\n  },\r\n\r\n  /** Get the font ascent for a given style\r\n   * @param {Object} style - The reference style\r\n   */\r\n  ascent: function(style) {\r\n  \tstyle = style || {};\r\n    return (style.size || CanvasText.style.size);\r\n  },\r\n  \r\n  /** Get the font descent for a given style \r\n   * @param {Object} style - The reference style\r\n   * */\r\n  descent: function(style) {\r\n  \tstyle = style || {};\r\n    return 7.0*(style.size || CanvasText.style.size)/25.0;\r\n  },\r\n  \r\n  /** Measure the text horizontal size \r\n   * @param {String} str - The text\r\n   * @param {Object} style - Text style\r\n   * */\r\n  measure: function(str, style) {\r\n    if (!str) return;\r\n    style = style || {};\r\n    \r\n    var i, width, lexemes = CanvasText.parseLexemes(str),\r\n        total = 0;\r\n\r\n    for (i = lexemes.length-1; i > -1; --i) {\r\n    \tc = lexemes[i];\r\n    \twidth = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width;\r\n      total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0;\r\n    }\r\n    return total;\r\n  },\r\n  \r\n  getDimensions: function(str, style) {\r\n    var width = CanvasText.measure(str, style),\r\n        height = style.size || CanvasText.style.size,\r\n        angle = style.angle || CanvasText.style.angle;\r\n\r\n    if (style.angle == 0) return {width: width, height: height};\r\n    return {\r\n      width:  Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height),\r\n      height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height)\r\n    }\r\n  },\r\n  \r\n  getBestAlign: function(angle, style) {\r\n    angle += CanvasText.getAngleFromAlign(style.halign, style.valign);\r\n    var a = {h:'c', v:'m'};\r\n    if (Math.round(Math.cos(angle)*1000)/1000 != 0) \r\n      a.h = (Math.cos(angle) > 0 ? 'r' : 'l');\r\n    \r\n    if (Math.round(Math.sin(angle)*1000)/1000 != 0) \r\n      a.v = (Math.sin(angle) > 0 ? 't' : 'b');\r\n    return a;\r\n  },\r\n  \r\n  getAngleFromAlign: function(halign, valign) {\r\n    var pi = Math.PI, table = {\r\n      'rm': 0,\r\n      'rt': pi/4,\r\n      'ct': pi/2,\r\n      'lt': 3*(pi/4),\r\n      'lm': pi,\r\n      'lb': -3*(pi/4),\r\n      'cb': -pi/2,\r\n      'rb': -pi/4,\r\n      'cm': 0\r\n    }\r\n    return table[halign+valign];\r\n  },\r\n  \r\n  /** Draws serie of points at given coordinates \r\n   * @param {Canvas context} ctx - The canvas context\r\n   * @param {Array} points - The points to draw\r\n   * @param {Number} x - The X coordinate\r\n   * @param {Number} y - The Y coordinate\r\n   * @param {Number} mag - The scale \r\n   */\r\n  drawPoints: function (ctx, points, x, y, mag, offset) {\r\n    var i, a, penUp = true, needStroke = 0;\r\n    offset = offset || {x:0, y:0};\r\n    \r\n    ctx.beginPath();\r\n    for (i = 0; i < points.length; i++) {\r\n      a = points[i];\r\n      if (!a) {\r\n        penUp = true;\r\n        continue;\r\n      }\r\n      if (penUp) {\r\n        ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);\r\n        penUp = false;\r\n      }\r\n      else {\r\n        ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);\r\n      }\r\n    }\r\n    ctx.stroke();\r\n  },\r\n  \r\n  /** Draws a text at given coordinates and with a given style\r\n   * @param {Canvas context} ctx - The canvas context\r\n   * @param {String} str - The text to draw\r\n   * @param {Number} xOrig - The X coordinate\r\n   * @param {Number} yOrig - The Y coordinate\r\n   * @param {Object} style - The font style\r\n   */\r\n  draw: function(ctx, str, xOrig, yOrig, style) {\r\n    if (!str) return;\r\n    style = style || CanvasText.style;\r\n    style.halign = style.halign || CanvasText.style.halign;\r\n    style.valign = style.valign || CanvasText.style.valign;\r\n    style.angle = style.angle || CanvasText.style.angle;\r\n    style.size = style.size || CanvasText.style.size;\r\n    style.adjustAlign = style.adjustAlign || CanvasText.style.adjustAlign;\r\n    \r\n    var i, c, total = 0,\r\n        mag = style.size / 25.0,\r\n        x = 0, y = 0,\r\n        lexemes = CanvasText.parseLexemes(str);\r\n    \r\n    var offset = {x:0, y:0}, \r\n        measure = CanvasText.measure(str, style),\r\n        align;\r\n        \r\n    if (style.adjustAlign) {\r\n      align = CanvasText.getBestAlign(style.angle, style);\r\n      style.halign = align.h;\r\n      style.valign = align.v;\r\n    }\r\n        \r\n    switch (style.halign) {\r\n      case 'l': break;\r\n      case 'c': offset.x = -measure / 2; break;\r\n      case 'r': offset.x = -measure; break;\r\n    }\r\n    \r\n    switch (style.valign) {\r\n      case 'b': break;\r\n      case 'm': offset.y = style.size / 2; break;\r\n      case 't': offset.y = style.size; break;\r\n    }\r\n    \r\n    ctx.save();\r\n    ctx.translate(xOrig, yOrig);\r\n    ctx.rotate(style.angle);\r\n    ctx.lineCap = \"round\";\r\n    ctx.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight);\r\n    ctx.strokeStyle = style.color || CanvasText.style.color;\r\n    \r\n    for (i = 0; i < lexemes.length; i++) {\r\n    \tc = lexemes[i];\r\n      if (c.width == -1) {\r\n        x = 0;\r\n        y = style.size * 1.4;\r\n        continue;\r\n      }\r\n    \r\n      var points = c.points,\r\n          width = c.width;\r\n          \r\n      if (c.diacritic) {\r\n        var dia = CanvasText.diacritics[c.diacritic];\r\n        var char = CanvasText.letter(c.letter);\r\n\r\n        CanvasText.drawPoints(ctx, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset);\r\n        points = char.points;\r\n        width = char.width;\r\n      }\r\n\r\n      CanvasText.drawPoints(ctx, points, x, y, mag, offset);\r\n      \r\n      if (CanvasText.debug) {\r\n      \tctx.save();\r\n        ctx.lineJoin = \"miter\";\r\n        ctx.lineWidth = 0.5;\r\n        ctx.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor);\r\n      \tctx.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size);\r\n        \r\n        ctx.fillStyle = (style.originPointColor || CanvasText.style.originPointColor);\r\n        ctx.beginPath();\r\n        ctx.arc(0, 0, 1.5, 0, Math.PI*2, true);\r\n        ctx.fill();\r\n        \r\n      \tctx.restore();\r\n      }\r\n      \r\n      x += width*mag*(style.tracking || CanvasText.style.tracking);\r\n    }\r\n    ctx.restore();\r\n    return total;\r\n  },\r\n  \r\n  /** Enables the text function for a Canvas context\r\n   * @param {Canvas context} ctx - The canvas context\r\n   */\r\n  enable: function(ctx) {\r\n    ctx.drawText    = function(text, x, y, style) { return CanvasText.draw(ctx, text, x, y, style); };\r\n    ctx.measureText = function(text, style) { return CanvasText.measure(text, style); };\r\n    ctx.getTextBounds = function(text, style) { return CanvasText.getDimensions(text, style); };\r\n    ctx.fontAscent  = function(style) { return CanvasText.ascent(style); };\r\n    ctx.fontDescent = function(style) { return CanvasText.descent(style); };\r\n  }\r\n};"
  },
  {
    "path": "input-scripts/flotr/lib/excanvas.js",
    "content": "// Copyright 2006 Google Inc.\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// Known Issues:\n//\n// * Patterns are not implemented.\n// * Radial gradient are not implemented. The VML version of these look very\n//   different from the canvas one.\n// * Clipping paths are not implemented.\n// * Coordsize. The width and height attribute have higher priority than the\n//   width and height style values which isn't correct.\n// * Painting mode isn't implemented.\n// * Canvas width/height should is using content-box by default. IE in\n//   Quirks mode will draw the canvas using border-box. Either change your\n//   doctype to HTML5\n//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)\n//   or use Box Sizing Behavior from WebFX\n//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)\n// * Non uniform scaling does not correctly scale strokes.\n// * Optimize. There is always room for speed improvements.\n\n// Only add this code if we do not already have a canvas implementation\nif (!document.createElement('canvas').getContext) {\n\n(function() {\n\n  // alias some functions to make (compiled) code shorter\n  var m = Math;\n  var mr = m.round;\n  var ms = m.sin;\n  var mc = m.cos;\n  var abs = m.abs;\n  var sqrt = m.sqrt;\n\n  // this is used for sub pixel precision\n  var Z = 10;\n  var Z2 = Z / 2;\n\n  /**\n   * This funtion is assigned to the <canvas> elements as element.getContext().\n   * @this {HTMLElement}\n   * @return {CanvasRenderingContext2D_}\n   */\n  function getContext() {\n    return this.context_ ||\n        (this.context_ = new CanvasRenderingContext2D_(this));\n  }\n\n  var slice = Array.prototype.slice;\n\n  /**\n   * Binds a function to an object. The returned function will always use the\n   * passed in {@code obj} as {@code this}.\n   *\n   * Example:\n   *\n   *   g = bind(f, obj, a, b)\n   *   g(c, d) // will do f.call(obj, a, b, c, d)\n   *\n   * @param {Function} f The function to bind the object to\n   * @param {Object} obj The object that should act as this when the function\n   *     is called\n   * @param {*} var_args Rest arguments that will be used as the initial\n   *     arguments when the function is called\n   * @return {Function} A new function that has bound this\n   */\n  function bind(f, obj, var_args) {\n    var a = slice.call(arguments, 2);\n    return function() {\n      return f.apply(obj, a.concat(slice.call(arguments)));\n    };\n  }\n\n  var G_vmlCanvasManager_ = {\n    init: function(opt_doc) {\n      if (/MSIE/.test(navigator.userAgent) && !window.opera) {\n        var doc = opt_doc || document;\n        // Create a dummy element so that IE will allow canvas elements to be\n        // recognized.\n        doc.createElement('canvas');\n        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));\n      }\n    },\n\n    init_: function(doc) {\n      // create xmlns\n      if (!doc.namespaces['g_vml_']) {\n        doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',\n                           '#default#VML');\n\n      }\n      if (!doc.namespaces['g_o_']) {\n        doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',\n                           '#default#VML');\n      }\n\n      // Setup default CSS.  Only add one style sheet per document\n      if (!doc.styleSheets['ex_canvas_']) {\n        var ss = doc.createStyleSheet();\n        ss.owningElement.id = 'ex_canvas_';\n        ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +\n            // default size is 300x150 in Gecko and Opera\n            'text-align:left;width:300px;height:150px}' +\n            'g_vml_\\\\:*{behavior:url(#default#VML)}' +\n            'g_o_\\\\:*{behavior:url(#default#VML)}';\n\n      }\n\n      // find all canvas elements\n      var els = doc.getElementsByTagName('canvas');\n      for (var i = 0; i < els.length; i++) {\n        this.initElement(els[i]);\n      }\n    },\n\n    /**\n     * Public initializes a canvas element so that it can be used as canvas\n     * element from now on. This is called automatically before the page is\n     * loaded but if you are creating elements using createElement you need to\n     * make sure this is called on the element.\n     * @param {HTMLElement} el The canvas element to initialize.\n     * @return {HTMLElement} the element that was created.\n     */\n    initElement: function(el) {\n      if (!el.getContext) {\n\n        el.getContext = getContext;\n\n        // Remove fallback content. There is no way to hide text nodes so we\n        // just remove all childNodes. We could hide all elements and remove\n        // text nodes but who really cares about the fallback content.\n        el.innerHTML = '';\n\n        // do not use inline function because that will leak memory\n        el.attachEvent('onpropertychange', onPropertyChange);\n        el.attachEvent('onresize', onResize);\n\n        var attrs = el.attributes;\n        if (attrs.width && attrs.width.specified) {\n          // TODO: use runtimeStyle and coordsize\n          // el.getContext().setWidth_(attrs.width.nodeValue);\n          el.style.width = attrs.width.nodeValue + 'px';\n        } else {\n          el.width = el.clientWidth;\n        }\n        if (attrs.height && attrs.height.specified) {\n          // TODO: use runtimeStyle and coordsize\n          // el.getContext().setHeight_(attrs.height.nodeValue);\n          el.style.height = attrs.height.nodeValue + 'px';\n        } else {\n          el.height = el.clientHeight;\n        }\n        //el.getContext().setCoordsize_()\n      }\n      return el;\n    }\n  };\n\n  function onPropertyChange(e) {\n    var el = e.srcElement;\n\n    switch (e.propertyName) {\n      case 'width':\n        el.style.width = el.attributes.width.nodeValue + 'px';\n        el.getContext().clearRect();\n        break;\n      case 'height':\n        el.style.height = el.attributes.height.nodeValue + 'px';\n        el.getContext().clearRect();\n        break;\n    }\n  }\n\n  function onResize(e) {\n    var el = e.srcElement;\n    if (el.firstChild) {\n      el.firstChild.style.width =  el.clientWidth + 'px';\n      el.firstChild.style.height = el.clientHeight + 'px';\n    }\n  }\n\n  G_vmlCanvasManager_.init();\n\n  // precompute \"00\" to \"FF\"\n  var dec2hex = [];\n  for (var i = 0; i < 16; i++) {\n    for (var j = 0; j < 16; j++) {\n      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);\n    }\n  }\n\n  function createMatrixIdentity() {\n    return [\n      [1, 0, 0],\n      [0, 1, 0],\n      [0, 0, 1]\n    ];\n  }\n\n  function matrixMultiply(m1, m2) {\n    var result = createMatrixIdentity();\n\n    for (var x = 0; x < 3; x++) {\n      for (var y = 0; y < 3; y++) {\n        var sum = 0;\n\n        for (var z = 0; z < 3; z++) {\n          sum += m1[x][z] * m2[z][y];\n        }\n\n        result[x][y] = sum;\n      }\n    }\n    return result;\n  }\n\n  function copyState(o1, o2) {\n    o2.fillStyle     = o1.fillStyle;\n    o2.lineCap       = o1.lineCap;\n    o2.lineJoin      = o1.lineJoin;\n    o2.lineWidth     = o1.lineWidth;\n    o2.miterLimit    = o1.miterLimit;\n    o2.shadowBlur    = o1.shadowBlur;\n    o2.shadowColor   = o1.shadowColor;\n    o2.shadowOffsetX = o1.shadowOffsetX;\n    o2.shadowOffsetY = o1.shadowOffsetY;\n    o2.strokeStyle   = o1.strokeStyle;\n    o2.globalAlpha   = o1.globalAlpha;\n    o2.arcScaleX_    = o1.arcScaleX_;\n    o2.arcScaleY_    = o1.arcScaleY_;\n    o2.lineScale_    = o1.lineScale_;\n  }\n\n  function processStyle(styleString) {\n    var str, alpha = 1;\n\n    styleString = String(styleString);\n    if (styleString.substring(0, 3) == 'rgb') {\n      var start = styleString.indexOf('(', 3);\n      var end = styleString.indexOf(')', start + 1);\n      var guts = styleString.substring(start + 1, end).split(',');\n\n      str = '#';\n      for (var i = 0; i < 3; i++) {\n        str += dec2hex[Number(guts[i])];\n      }\n\n      if (guts.length == 4 && styleString.substr(3, 1) == 'a') {\n        alpha = guts[3];\n      }\n    } else {\n      str = styleString;\n    }\n\n    return {color: str, alpha: alpha};\n  }\n\n  function processLineCap(lineCap) {\n    switch (lineCap) {\n      case 'butt':\n        return 'flat';\n      case 'round':\n        return 'round';\n      case 'square':\n      default:\n        return 'square';\n    }\n  }\n\n  /**\n   * This class implements CanvasRenderingContext2D interface as described by\n   * the WHATWG.\n   * @param {HTMLElement} surfaceElement The element that the 2D context should\n   * be associated with\n   */\n  function CanvasRenderingContext2D_(surfaceElement) {\n    this.m_ = createMatrixIdentity();\n\n    this.mStack_ = [];\n    this.aStack_ = [];\n    this.currentPath_ = [];\n\n    // Canvas context properties\n    this.strokeStyle = '#000';\n    this.fillStyle = '#000';\n\n    this.lineWidth = 1;\n    this.lineJoin = 'miter';\n    this.lineCap = 'butt';\n    this.miterLimit = Z * 1;\n    this.globalAlpha = 1;\n    this.canvas = surfaceElement;\n\n    var el = surfaceElement.ownerDocument.createElement('div');\n    el.style.width =  surfaceElement.clientWidth + 'px';\n    el.style.height = surfaceElement.clientHeight + 'px';\n    el.style.overflow = 'hidden';\n    el.style.position = 'absolute';\n    surfaceElement.appendChild(el);\n\n    this.element_ = el;\n    this.arcScaleX_ = 1;\n    this.arcScaleY_ = 1;\n    this.lineScale_ = 1;\n  }\n\n  var contextPrototype = CanvasRenderingContext2D_.prototype;\n  contextPrototype.clearRect = function() {\n    this.element_.innerHTML = '';\n  };\n\n  contextPrototype.beginPath = function() {\n    // TODO: Branch current matrix so that save/restore has no effect\n    //       as per safari docs.\n    this.currentPath_ = [];\n  };\n\n  contextPrototype.moveTo = function(aX, aY) {\n    var p = this.getCoords_(aX, aY);\n    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});\n    this.currentX_ = p.x;\n    this.currentY_ = p.y;\n  };\n\n  contextPrototype.lineTo = function(aX, aY) {\n    var p = this.getCoords_(aX, aY);\n    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});\n\n    this.currentX_ = p.x;\n    this.currentY_ = p.y;\n  };\n\n  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,\n                                            aCP2x, aCP2y,\n                                            aX, aY) {\n    var p = this.getCoords_(aX, aY);\n    var cp1 = this.getCoords_(aCP1x, aCP1y);\n    var cp2 = this.getCoords_(aCP2x, aCP2y);\n    bezierCurveTo(this, cp1, cp2, p);\n  };\n\n  // Helper function that takes the already fixed cordinates.\n  function bezierCurveTo(self, cp1, cp2, p) {\n    self.currentPath_.push({\n      type: 'bezierCurveTo',\n      cp1x: cp1.x,\n      cp1y: cp1.y,\n      cp2x: cp2.x,\n      cp2y: cp2.y,\n      x: p.x,\n      y: p.y\n    });\n    self.currentX_ = p.x;\n    self.currentY_ = p.y;\n  }\n\n  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {\n    // the following is lifted almost directly from\n    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes\n\n    var cp = this.getCoords_(aCPx, aCPy);\n    var p = this.getCoords_(aX, aY);\n\n    var cp1 = {\n      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),\n      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)\n    };\n    var cp2 = {\n      x: cp1.x + (p.x - this.currentX_) / 3.0,\n      y: cp1.y + (p.y - this.currentY_) / 3.0\n    };\n\n    bezierCurveTo(this, cp1, cp2, p);\n  };\n\n  contextPrototype.arc = function(aX, aY, aRadius,\n                                  aStartAngle, aEndAngle, aClockwise) {\n    aRadius *= Z;\n    var arcType = aClockwise ? 'at' : 'wa';\n\n    var xStart = aX + mc(aStartAngle) * aRadius - Z2;\n    var yStart = aY + ms(aStartAngle) * aRadius - Z2;\n\n    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;\n    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;\n\n    // IE won't render arches drawn counter clockwise if xStart == xEnd.\n    if (xStart == xEnd && !aClockwise) {\n      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something\n                       // that can be represented in binary\n    }\n\n    var p = this.getCoords_(aX, aY);\n    var pStart = this.getCoords_(xStart, yStart);\n    var pEnd = this.getCoords_(xEnd, yEnd);\n\n    this.currentPath_.push({type: arcType,\n                           x: p.x,\n                           y: p.y,\n                           radius: aRadius,\n                           xStart: pStart.x,\n                           yStart: pStart.y,\n                           xEnd: pEnd.x,\n                           yEnd: pEnd.y});\n\n  };\n\n  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n  };\n\n  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {\n    var oldPath = this.currentPath_;\n    this.beginPath();\n\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n    this.stroke();\n\n    this.currentPath_ = oldPath;\n  };\n\n  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {\n    var oldPath = this.currentPath_;\n    this.beginPath();\n\n    this.moveTo(aX, aY);\n    this.lineTo(aX + aWidth, aY);\n    this.lineTo(aX + aWidth, aY + aHeight);\n    this.lineTo(aX, aY + aHeight);\n    this.closePath();\n    this.fill();\n\n    this.currentPath_ = oldPath;\n  };\n\n  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {\n    var gradient = new CanvasGradient_('gradient');\n    gradient.x0_ = aX0;\n    gradient.y0_ = aY0;\n    gradient.x1_ = aX1;\n    gradient.y1_ = aY1;\n    return gradient;\n  };\n\n  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,\n                                                   aX1, aY1, aR1) {\n    var gradient = new CanvasGradient_('gradientradial');\n    gradient.x0_ = aX0;\n    gradient.y0_ = aY0;\n    gradient.r0_ = aR0;\n    gradient.x1_ = aX1;\n    gradient.y1_ = aY1;\n    gradient.r1_ = aR1;\n    return gradient;\n  };\n\n  contextPrototype.drawImage = function(image, var_args) {\n    var dx, dy, dw, dh, sx, sy, sw, sh;\n\n    // to find the original width we overide the width and height\n    var oldRuntimeWidth = image.runtimeStyle.width;\n    var oldRuntimeHeight = image.runtimeStyle.height;\n    image.runtimeStyle.width = 'auto';\n    image.runtimeStyle.height = 'auto';\n\n    // get the original size\n    var w = image.width;\n    var h = image.height;\n\n    // and remove overides\n    image.runtimeStyle.width = oldRuntimeWidth;\n    image.runtimeStyle.height = oldRuntimeHeight;\n\n    if (arguments.length == 3) {\n      dx = arguments[1];\n      dy = arguments[2];\n      sx = sy = 0;\n      sw = dw = w;\n      sh = dh = h;\n    } else if (arguments.length == 5) {\n      dx = arguments[1];\n      dy = arguments[2];\n      dw = arguments[3];\n      dh = arguments[4];\n      sx = sy = 0;\n      sw = w;\n      sh = h;\n    } else if (arguments.length == 9) {\n      sx = arguments[1];\n      sy = arguments[2];\n      sw = arguments[3];\n      sh = arguments[4];\n      dx = arguments[5];\n      dy = arguments[6];\n      dw = arguments[7];\n      dh = arguments[8];\n    } else {\n      throw Error('Invalid number of arguments');\n    }\n\n    var d = this.getCoords_(dx, dy);\n\n    var w2 = sw / 2;\n    var h2 = sh / 2;\n\n    var vmlStr = [];\n\n    var W = 10;\n    var H = 10;\n\n    // For some reason that I've now forgotten, using divs didn't work\n    vmlStr.push(' <g_vml_:group',\n                ' coordsize=\"', Z * W, ',', Z * H, '\"',\n                ' coordorigin=\"0,0\"' ,\n                ' style=\"width:', W, 'px;height:', H, 'px;position:absolute;');\n\n    // If filters are necessary (rotation exists), create them\n    // filters are bog-slow, so only create them if abbsolutely necessary\n    // The following check doesn't account for skews (which don't exist\n    // in the canvas spec (yet) anyway.\n\n    if (this.m_[0][0] != 1 || this.m_[0][1]) {\n      var filter = [];\n\n      // Note the 12/21 reversal\n      filter.push('M11=', this.m_[0][0], ',',\n                  'M12=', this.m_[1][0], ',',\n                  'M21=', this.m_[0][1], ',',\n                  'M22=', this.m_[1][1], ',',\n                  'Dx=', mr(d.x / Z), ',',\n                  'Dy=', mr(d.y / Z), '');\n\n      // Bounding box calculation (need to minimize displayed area so that\n      // filters don't waste time on unused pixels.\n      var max = d;\n      var c2 = this.getCoords_(dx + dw, dy);\n      var c3 = this.getCoords_(dx, dy + dh);\n      var c4 = this.getCoords_(dx + dw, dy + dh);\n\n      max.x = m.max(max.x, c2.x, c3.x, c4.x);\n      max.y = m.max(max.y, c2.y, c3.y, c4.y);\n\n      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),\n                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',\n                  filter.join(''), \", sizingmethod='clip');\")\n    } else {\n      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');\n    }\n\n    vmlStr.push(' \">' ,\n                '<g_vml_:image src=\"', image.src, '\"',\n                ' style=\"width:', Z * dw, 'px;',\n                ' height:', Z * dh, 'px;\"',\n                ' cropleft=\"', sx / w, '\"',\n                ' croptop=\"', sy / h, '\"',\n                ' cropright=\"', (w - sx - sw) / w, '\"',\n                ' cropbottom=\"', (h - sy - sh) / h, '\"',\n                ' />',\n                '</g_vml_:group>');\n\n    this.element_.insertAdjacentHTML('BeforeEnd',\n                                    vmlStr.join(''));\n  };\n\n  contextPrototype.stroke = function(aFill) {\n    var lineStr = [];\n    var lineOpen = false;\n    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);\n    var color = a.color;\n    var opacity = a.alpha * this.globalAlpha;\n\n    var W = 10;\n    var H = 10;\n\n    lineStr.push('<g_vml_:shape',\n                 ' filled=\"', !!aFill, '\"',\n                 ' style=\"position:absolute;width:', W, 'px;height:', H, 'px;\"',\n                 ' coordorigin=\"0 0\" coordsize=\"', Z * W, ' ', Z * H, '\"',\n                 ' stroked=\"', !aFill, '\"',\n                 ' path=\"');\n\n    var newSeq = false;\n    var min = {x: null, y: null};\n    var max = {x: null, y: null};\n\n    for (var i = 0; i < this.currentPath_.length; i++) {\n      var p = this.currentPath_[i];\n      var c;\n\n      switch (p.type) {\n        case 'moveTo':\n          c = p;\n          lineStr.push(' m ', mr(p.x), ',', mr(p.y));\n          break;\n        case 'lineTo':\n          lineStr.push(' l ', mr(p.x), ',', mr(p.y));\n          break;\n        case 'close':\n          lineStr.push(' x ');\n          p = null;\n          break;\n        case 'bezierCurveTo':\n          lineStr.push(' c ',\n                       mr(p.cp1x), ',', mr(p.cp1y), ',',\n                       mr(p.cp2x), ',', mr(p.cp2y), ',',\n                       mr(p.x), ',', mr(p.y));\n          break;\n        case 'at':\n        case 'wa':\n          lineStr.push(' ', p.type, ' ',\n                       mr(p.x - this.arcScaleX_ * p.radius), ',',\n                       mr(p.y - this.arcScaleY_ * p.radius), ' ',\n                       mr(p.x + this.arcScaleX_ * p.radius), ',',\n                       mr(p.y + this.arcScaleY_ * p.radius), ' ',\n                       mr(p.xStart), ',', mr(p.yStart), ' ',\n                       mr(p.xEnd), ',', mr(p.yEnd));\n          break;\n      }\n\n\n      // TODO: Following is broken for curves due to\n      //       move to proper paths.\n\n      // Figure out dimensions so we can do gradient fills\n      // properly\n      if (p) {\n        if (min.x == null || p.x < min.x) {\n          min.x = p.x;\n        }\n        if (max.x == null || p.x > max.x) {\n          max.x = p.x;\n        }\n        if (min.y == null || p.y < min.y) {\n          min.y = p.y;\n        }\n        if (max.y == null || p.y > max.y) {\n          max.y = p.y;\n        }\n      }\n    }\n    lineStr.push(' \">');\n\n    if (!aFill) {\n      var lineWidth = this.lineScale_ * this.lineWidth;\n\n      // VML cannot correctly render a line if the width is less than 1px.\n      // In that case, we dilute the color to make the line look thinner.\n      if (lineWidth < 1) {\n        opacity *= lineWidth;\n      }\n\n      lineStr.push(\n        '<g_vml_:stroke',\n        ' opacity=\"', opacity, '\"',\n        ' joinstyle=\"', this.lineJoin, '\"',\n        ' miterlimit=\"', this.miterLimit, '\"',\n        ' endcap=\"', processLineCap(this.lineCap), '\"',\n        ' weight=\"', lineWidth, 'px\"',\n        ' color=\"', color, '\" />'\n      );\n    } else if (typeof this.fillStyle == 'object') {\n      var fillStyle = this.fillStyle;\n      var angle = 0;\n      var focus = {x: 0, y: 0};\n\n      // additional offset\n      var shift = 0;\n      // scale factor for offset\n      var expansion = 1;\n\n      if (fillStyle.type_ == 'gradient') {\n        var x0 = fillStyle.x0_ / this.arcScaleX_;\n        var y0 = fillStyle.y0_ / this.arcScaleY_;\n        var x1 = fillStyle.x1_ / this.arcScaleX_;\n        var y1 = fillStyle.y1_ / this.arcScaleY_;\n        var p0 = this.getCoords_(x0, y0);\n        var p1 = this.getCoords_(x1, y1);\n        var dx = p1.x - p0.x;\n        var dy = p1.y - p0.y;\n        angle = Math.atan2(dx, dy) * 180 / Math.PI;\n\n        // The angle should be a non-negative number.\n        if (angle < 0) {\n          angle += 360;\n        }\n\n        // Very small angles produce an unexpected result because they are\n        // converted to a scientific notation string.\n        if (angle < 1e-6) {\n          angle = 0;\n        }\n      } else {\n        var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);\n        var width  = max.x - min.x;\n        var height = max.y - min.y;\n        focus = {\n          x: (p0.x - min.x) / width,\n          y: (p0.y - min.y) / height\n        };\n\n        width  /= this.arcScaleX_ * Z;\n        height /= this.arcScaleY_ * Z;\n        var dimension = m.max(width, height);\n        shift = 2 * fillStyle.r0_ / dimension;\n        expansion = 2 * fillStyle.r1_ / dimension - shift;\n      }\n\n      // We need to sort the color stops in ascending order by offset,\n      // otherwise IE won't interpret it correctly.\n      var stops = fillStyle.colors_;\n      stops.sort(function(cs1, cs2) {\n        return cs1.offset - cs2.offset;\n      });\n\n      var length = stops.length;\n      var color1 = stops[0].color;\n      var color2 = stops[length - 1].color;\n      var opacity1 = stops[0].alpha * this.globalAlpha;\n      var opacity2 = stops[length - 1].alpha * this.globalAlpha;\n\n      var colors = [];\n      for (var i = 0; i < length; i++) {\n        var stop = stops[i];\n        colors.push(stop.offset * expansion + shift + ' ' + stop.color);\n      }\n\n      // When colors attribute is used, the meanings of opacity and o:opacity2\n      // are reversed.\n      lineStr.push('<g_vml_:fill type=\"', fillStyle.type_, '\"',\n                   ' method=\"none\" focus=\"100%\"',\n                   ' color=\"', color1, '\"',\n                   ' color2=\"', color2, '\"',\n                   ' colors=\"', colors.join(','), '\"',\n                   ' opacity=\"', opacity2, '\"',\n                   ' g_o_:opacity2=\"', opacity1, '\"',\n                   ' angle=\"', angle, '\"',\n                   ' focusposition=\"', focus.x, ',', focus.y, '\" />');\n    } else {\n      lineStr.push('<g_vml_:fill color=\"', color, '\" opacity=\"', opacity,\n                   '\" />');\n    }\n\n    lineStr.push('</g_vml_:shape>');\n\n    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));\n  };\n\n  contextPrototype.fill = function() {\n    this.stroke(true);\n  }\n\n  contextPrototype.closePath = function() {\n    this.currentPath_.push({type: 'close'});\n  };\n\n  /**\n   * @private\n   */\n  contextPrototype.getCoords_ = function(aX, aY) {\n    var m = this.m_;\n    return {\n      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,\n      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2\n    }\n  };\n\n  contextPrototype.save = function() {\n    var o = {};\n    copyState(this, o);\n    this.aStack_.push(o);\n    this.mStack_.push(this.m_);\n    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);\n  };\n\n  contextPrototype.restore = function() {\n    copyState(this.aStack_.pop(), this);\n    this.m_ = this.mStack_.pop();\n  };\n\n  contextPrototype.translate = function(aX, aY) {\n    var m1 = [\n      [1,  0,  0],\n      [0,  1,  0],\n      [aX, aY, 1]\n    ];\n\n    this.m_ = matrixMultiply(m1, this.m_);\n  };\n\n  contextPrototype.rotate = function(aRot) {\n    var c = mc(aRot);\n    var s = ms(aRot);\n\n    var m1 = [\n      [c,  s, 0],\n      [-s, c, 0],\n      [0,  0, 1]\n    ];\n\n    this.m_ = matrixMultiply(m1, this.m_);\n  };\n\n  contextPrototype.scale = function(aX, aY) {\n    this.arcScaleX_ *= aX;\n    this.arcScaleY_ *= aY;\n    var m1 = [\n      [aX, 0,  0],\n      [0,  aY, 0],\n      [0,  0,  1]\n    ];\n\n    var m = this.m_ = matrixMultiply(m1, this.m_);\n\n    // Get the line scale.\n    // Determinant of this.m_ means how much the area is enlarged by the\n    // transformation. So its square root can be used as a scale factor\n    // for width.\n    var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];\n    this.lineScale_ = sqrt(abs(det));\n  };\n\n  /******** STUBS ********/\n  contextPrototype.clip = function() {\n    // TODO: Implement\n  };\n\n  contextPrototype.arcTo = function() {\n    // TODO: Implement\n  };\n\n  contextPrototype.createPattern = function() {\n    return new CanvasPattern_;\n  };\n\n  // Gradient / Pattern Stubs\n  function CanvasGradient_(aType) {\n    this.type_ = aType;\n    this.x0_ = 0;\n    this.y0_ = 0;\n    this.r0_ = 0;\n    this.x1_ = 0;\n    this.y1_ = 0;\n    this.r1_ = 0;\n    this.colors_ = [];\n  }\n\n  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {\n    aColor = processStyle(aColor);\n    this.colors_.push({offset: aOffset,\n                       color: aColor.color,\n                       alpha: aColor.alpha});\n  };\n\n  function CanvasPattern_() {}\n\n  // set up externs\n  G_vmlCanvasManager = G_vmlCanvasManager_;\n  CanvasRenderingContext2D = CanvasRenderingContext2D_;\n  CanvasGradient = CanvasGradient_;\n  CanvasPattern = CanvasPattern_;\n\n})();\n\n} // if\n"
  },
  {
    "path": "input-scripts/flotr/lib/prototype-1.6.0.2.js",
    "content": "/*  Prototype JavaScript framework, version 1.6.0.2\r\n *  (c) 2005-2008 Sam Stephenson\r\n *\r\n *  Prototype is freely distributable under the terms of an MIT-style license.\r\n *  For details, see the Prototype web site: http://www.prototypejs.org/\r\n *\r\n *--------------------------------------------------------------------------*/\r\n\r\nvar Prototype = {\r\n  Version: '1.6.0.2',\r\n\r\n  Browser: {\r\n    IE:     !!(window.attachEvent && !window.opera),\r\n    Opera:  !!window.opera,\r\n    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,\r\n    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,\r\n    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)\r\n  },\r\n\r\n  BrowserFeatures: {\r\n    XPath: !!document.evaluate,\r\n    ElementExtensions: !!window.HTMLElement,\r\n    SpecificElementExtensions:\r\n      document.createElement('div').__proto__ &&\r\n      document.createElement('div').__proto__ !==\r\n        document.createElement('form').__proto__\r\n  },\r\n\r\n  ScriptFragment: '<script[^>]*>([\\\\S\\\\s]*?)<\\/script>',\r\n  JSONFilter: /^\\/\\*-secure-([\\s\\S]*)\\*\\/\\s*$/,\r\n\r\n  emptyFunction: function() { },\r\n  K: function(x) { return x }\r\n};\r\n\r\nif (Prototype.Browser.MobileSafari)\r\n  Prototype.BrowserFeatures.SpecificElementExtensions = false;\r\n\r\n\r\n/* Based on Alex Arnell's inheritance implementation. */\r\nvar Class = {\r\n  create: function() {\r\n    var parent = null, properties = $A(arguments);\r\n    if (Object.isFunction(properties[0]))\r\n      parent = properties.shift();\r\n\r\n    function klass() {\r\n      this.initialize.apply(this, arguments);\r\n    }\r\n\r\n    Object.extend(klass, Class.Methods);\r\n    klass.superclass = parent;\r\n    klass.subclasses = [];\r\n\r\n    if (parent) {\r\n      var subclass = function() { };\r\n      subclass.prototype = parent.prototype;\r\n      klass.prototype = new subclass;\r\n      parent.subclasses.push(klass);\r\n    }\r\n\r\n    for (var i = 0; i < properties.length; i++)\r\n      klass.addMethods(properties[i]);\r\n\r\n    if (!klass.prototype.initialize)\r\n      klass.prototype.initialize = Prototype.emptyFunction;\r\n\r\n    klass.prototype.constructor = klass;\r\n\r\n    return klass;\r\n  }\r\n};\r\n\r\nClass.Methods = {\r\n  addMethods: function(source) {\r\n    var ancestor   = this.superclass && this.superclass.prototype;\r\n    var properties = Object.keys(source);\r\n\r\n    if (!Object.keys({ toString: true }).length)\r\n      properties.push(\"toString\", \"valueOf\");\r\n\r\n    for (var i = 0, length = properties.length; i < length; i++) {\r\n      var property = properties[i], value = source[property];\r\n      if (ancestor && Object.isFunction(value) &&\r\n          value.argumentNames().first() == \"$super\") {\r\n        var method = value, value = Object.extend((function(m) {\r\n          return function() { return ancestor[m].apply(this, arguments) };\r\n        })(property).wrap(method), {\r\n          valueOf:  function() { return method },\r\n          toString: function() { return method.toString() }\r\n        });\r\n      }\r\n      this.prototype[property] = value;\r\n    }\r\n\r\n    return this;\r\n  }\r\n};\r\n\r\nvar Abstract = { };\r\n\r\nObject.extend = function(destination, source) {\r\n  for (var property in source)\r\n    destination[property] = source[property];\r\n  return destination;\r\n};\r\n\r\nObject.extend(Object, {\r\n  inspect: function(object) {\r\n    try {\r\n      if (Object.isUndefined(object)) return 'undefined';\r\n      if (object === null) return 'null';\r\n      return object.inspect ? object.inspect() : String(object);\r\n    } catch (e) {\r\n      if (e instanceof RangeError) return '...';\r\n      throw e;\r\n    }\r\n  },\r\n\r\n  toJSON: function(object) {\r\n    var type = typeof object;\r\n    switch (type) {\r\n      case 'undefined':\r\n      case 'function':\r\n      case 'unknown': return;\r\n      case 'boolean': return object.toString();\r\n    }\r\n\r\n    if (object === null) return 'null';\r\n    if (object.toJSON) return object.toJSON();\r\n    if (Object.isElement(object)) return;\r\n\r\n    var results = [];\r\n    for (var property in object) {\r\n      var value = Object.toJSON(object[property]);\r\n      if (!Object.isUndefined(value))\r\n        results.push(property.toJSON() + ': ' + value);\r\n    }\r\n\r\n    return '{' + results.join(', ') + '}';\r\n  },\r\n\r\n  toQueryString: function(object) {\r\n    return $H(object).toQueryString();\r\n  },\r\n\r\n  toHTML: function(object) {\r\n    return object && object.toHTML ? object.toHTML() : String.interpret(object);\r\n  },\r\n\r\n  keys: function(object) {\r\n    var keys = [];\r\n    for (var property in object)\r\n      keys.push(property);\r\n    return keys;\r\n  },\r\n\r\n  values: function(object) {\r\n    var values = [];\r\n    for (var property in object)\r\n      values.push(object[property]);\r\n    return values;\r\n  },\r\n\r\n  clone: function(object) {\r\n    return Object.extend({ }, object);\r\n  },\r\n\r\n  isElement: function(object) {\r\n    return object && object.nodeType == 1;\r\n  },\r\n\r\n  isArray: function(object) {\r\n    return object != null && typeof object == \"object\" &&\r\n      'splice' in object && 'join' in object;\r\n  },\r\n\r\n  isHash: function(object) {\r\n    return object instanceof Hash;\r\n  },\r\n\r\n  isFunction: function(object) {\r\n    return typeof object == \"function\";\r\n  },\r\n\r\n  isString: function(object) {\r\n    return typeof object == \"string\";\r\n  },\r\n\r\n  isNumber: function(object) {\r\n    return typeof object == \"number\";\r\n  },\r\n\r\n  isUndefined: function(object) {\r\n    return typeof object == \"undefined\";\r\n  }\r\n});\r\n\r\nObject.extend(Function.prototype, {\r\n  argumentNames: function() {\r\n    var names = this.toString().match(/^[\\s\\(]*function[^(]*\\((.*?)\\)/)[1].split(\",\").invoke(\"strip\");\r\n    return names.length == 1 && !names[0] ? [] : names;\r\n  },\r\n\r\n  bind: function() {\r\n    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;\r\n    var __method = this, args = $A(arguments), object = args.shift();\r\n    return function() {\r\n      return __method.apply(object, args.concat($A(arguments)));\r\n    }\r\n  },\r\n\r\n  bindAsEventListener: function() {\r\n    var __method = this, args = $A(arguments), object = args.shift();\r\n    return function(event) {\r\n      return __method.apply(object, [event || window.event].concat(args));\r\n    }\r\n  },\r\n\r\n  curry: function() {\r\n    if (!arguments.length) return this;\r\n    var __method = this, args = $A(arguments);\r\n    return function() {\r\n      return __method.apply(this, args.concat($A(arguments)));\r\n    }\r\n  },\r\n\r\n  delay: function() {\r\n    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;\r\n    return window.setTimeout(function() {\r\n      return __method.apply(__method, args);\r\n    }, timeout);\r\n  },\r\n\r\n  wrap: function(wrapper) {\r\n    var __method = this;\r\n    return function() {\r\n      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));\r\n    }\r\n  },\r\n\r\n  methodize: function() {\r\n    if (this._methodized) return this._methodized;\r\n    var __method = this;\r\n    return this._methodized = function() {\r\n      return __method.apply(null, [this].concat($A(arguments)));\r\n    };\r\n  }\r\n});\r\n\r\nFunction.prototype.defer = Function.prototype.delay.curry(0.01);\r\n\r\nDate.prototype.toJSON = function() {\r\n  return '\"' + this.getUTCFullYear() + '-' +\r\n    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +\r\n    this.getUTCDate().toPaddedString(2) + 'T' +\r\n    this.getUTCHours().toPaddedString(2) + ':' +\r\n    this.getUTCMinutes().toPaddedString(2) + ':' +\r\n    this.getUTCSeconds().toPaddedString(2) + 'Z\"';\r\n};\r\n\r\nvar Try = {\r\n  these: function() {\r\n    var returnValue;\r\n\r\n    for (var i = 0, length = arguments.length; i < length; i++) {\r\n      var lambda = arguments[i];\r\n      try {\r\n        returnValue = lambda();\r\n        break;\r\n      } catch (e) { }\r\n    }\r\n\r\n    return returnValue;\r\n  }\r\n};\r\n\r\nRegExp.prototype.match = RegExp.prototype.test;\r\n\r\nRegExp.escape = function(str) {\r\n  return String(str).replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$1');\r\n};\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nvar PeriodicalExecuter = Class.create({\r\n  initialize: function(callback, frequency) {\r\n    this.callback = callback;\r\n    this.frequency = frequency;\r\n    this.currentlyExecuting = false;\r\n\r\n    this.registerCallback();\r\n  },\r\n\r\n  registerCallback: function() {\r\n    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\r\n  },\r\n\r\n  execute: function() {\r\n    this.callback(this);\r\n  },\r\n\r\n  stop: function() {\r\n    if (!this.timer) return;\r\n    clearInterval(this.timer);\r\n    this.timer = null;\r\n  },\r\n\r\n  onTimerEvent: function() {\r\n    if (!this.currentlyExecuting) {\r\n      try {\r\n        this.currentlyExecuting = true;\r\n        this.execute();\r\n      } finally {\r\n        this.currentlyExecuting = false;\r\n      }\r\n    }\r\n  }\r\n});\r\nObject.extend(String, {\r\n  interpret: function(value) {\r\n    return value == null ? '' : String(value);\r\n  },\r\n  specialChar: {\r\n    '\\b': '\\\\b',\r\n    '\\t': '\\\\t',\r\n    '\\n': '\\\\n',\r\n    '\\f': '\\\\f',\r\n    '\\r': '\\\\r',\r\n    '\\\\': '\\\\\\\\'\r\n  }\r\n});\r\n\r\nObject.extend(String.prototype, {\r\n  gsub: function(pattern, replacement) {\r\n    var result = '', source = this, match;\r\n    replacement = arguments.callee.prepareReplacement(replacement);\r\n\r\n    while (source.length > 0) {\r\n      if (match = source.match(pattern)) {\r\n        result += source.slice(0, match.index);\r\n        result += String.interpret(replacement(match));\r\n        source  = source.slice(match.index + match[0].length);\r\n      } else {\r\n        result += source, source = '';\r\n      }\r\n    }\r\n    return result;\r\n  },\r\n\r\n  sub: function(pattern, replacement, count) {\r\n    replacement = this.gsub.prepareReplacement(replacement);\r\n    count = Object.isUndefined(count) ? 1 : count;\r\n\r\n    return this.gsub(pattern, function(match) {\r\n      if (--count < 0) return match[0];\r\n      return replacement(match);\r\n    });\r\n  },\r\n\r\n  scan: function(pattern, iterator) {\r\n    this.gsub(pattern, iterator);\r\n    return String(this);\r\n  },\r\n\r\n  truncate: function(length, truncation) {\r\n    length = length || 30;\r\n    truncation = Object.isUndefined(truncation) ? '...' : truncation;\r\n    return this.length > length ?\r\n      this.slice(0, length - truncation.length) + truncation : String(this);\r\n  },\r\n\r\n  strip: function() {\r\n    return this.replace(/^\\s+/, '').replace(/\\s+$/, '');\r\n  },\r\n\r\n  stripTags: function() {\r\n    return this.replace(/<\\/?[^>]+>/gi, '');\r\n  },\r\n\r\n  stripScripts: function() {\r\n    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');\r\n  },\r\n\r\n  extractScripts: function() {\r\n    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');\r\n    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');\r\n    return (this.match(matchAll) || []).map(function(scriptTag) {\r\n      return (scriptTag.match(matchOne) || ['', ''])[1];\r\n    });\r\n  },\r\n\r\n  evalScripts: function() {\r\n    return this.extractScripts().map(function(script) { return eval(script) });\r\n  },\r\n\r\n  escapeHTML: function() {\r\n    var self = arguments.callee;\r\n    self.text.data = this;\r\n    return self.div.innerHTML;\r\n  },\r\n\r\n  unescapeHTML: function() {\r\n    var div = new Element('div');\r\n    div.innerHTML = this.stripTags();\r\n    return div.childNodes[0] ? (div.childNodes.length > 1 ?\r\n      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :\r\n      div.childNodes[0].nodeValue) : '';\r\n  },\r\n\r\n  toQueryParams: function(separator) {\r\n    var match = this.strip().match(/([^?#]*)(#.*)?$/);\r\n    if (!match) return { };\r\n\r\n    return match[1].split(separator || '&').inject({ }, function(hash, pair) {\r\n      if ((pair = pair.split('='))[0]) {\r\n        var key = decodeURIComponent(pair.shift());\r\n        var value = pair.length > 1 ? pair.join('=') : pair[0];\r\n        if (value != undefined) value = decodeURIComponent(value);\r\n\r\n        if (key in hash) {\r\n          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];\r\n          hash[key].push(value);\r\n        }\r\n        else hash[key] = value;\r\n      }\r\n      return hash;\r\n    });\r\n  },\r\n\r\n  toArray: function() {\r\n    return this.split('');\r\n  },\r\n\r\n  succ: function() {\r\n    return this.slice(0, this.length - 1) +\r\n      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);\r\n  },\r\n\r\n  times: function(count) {\r\n    return count < 1 ? '' : new Array(count + 1).join(this);\r\n  },\r\n\r\n  camelize: function() {\r\n    var parts = this.split('-'), len = parts.length;\r\n    if (len == 1) return parts[0];\r\n\r\n    var camelized = this.charAt(0) == '-'\r\n      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)\r\n      : parts[0];\r\n\r\n    for (var i = 1; i < len; i++)\r\n      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);\r\n\r\n    return camelized;\r\n  },\r\n\r\n  capitalize: function() {\r\n    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();\r\n  },\r\n\r\n  underscore: function() {\r\n    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();\r\n  },\r\n\r\n  dasherize: function() {\r\n    return this.gsub(/_/,'-');\r\n  },\r\n\r\n  inspect: function(useDoubleQuotes) {\r\n    var escapedString = this.gsub(/[\\x00-\\x1f\\\\]/, function(match) {\r\n      var character = String.specialChar[match[0]];\r\n      return character ? character : '\\\\u00' + match[0].charCodeAt().toPaddedString(2, 16);\r\n    });\r\n    if (useDoubleQuotes) return '\"' + escapedString.replace(/\"/g, '\\\\\"') + '\"';\r\n    return \"'\" + escapedString.replace(/'/g, '\\\\\\'') + \"'\";\r\n  },\r\n\r\n  toJSON: function() {\r\n    return this.inspect(true);\r\n  },\r\n\r\n  unfilterJSON: function(filter) {\r\n    return this.sub(filter || Prototype.JSONFilter, '#{1}');\r\n  },\r\n\r\n  isJSON: function() {\r\n    var str = this;\r\n    if (str.blank()) return false;\r\n    str = this.replace(/\\\\./g, '@').replace(/\"[^\"\\\\\\n\\r]*\"/g, '');\r\n    return (/^[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]*$/).test(str);\r\n  },\r\n\r\n  evalJSON: function(sanitize) {\r\n    var json = this.unfilterJSON();\r\n    try {\r\n      if (!sanitize || json.isJSON()) return eval('(' + json + ')');\r\n    } catch (e) { }\r\n    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());\r\n  },\r\n\r\n  include: function(pattern) {\r\n    return this.indexOf(pattern) > -1;\r\n  },\r\n\r\n  startsWith: function(pattern) {\r\n    return this.indexOf(pattern) === 0;\r\n  },\r\n\r\n  endsWith: function(pattern) {\r\n    var d = this.length - pattern.length;\r\n    return d >= 0 && this.lastIndexOf(pattern) === d;\r\n  },\r\n\r\n  empty: function() {\r\n    return this == '';\r\n  },\r\n\r\n  blank: function() {\r\n    return /^\\s*$/.test(this);\r\n  },\r\n\r\n  interpolate: function(object, pattern) {\r\n    return new Template(this, pattern).evaluate(object);\r\n  }\r\n});\r\n\r\nif (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {\r\n  escapeHTML: function() {\r\n    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\r\n  },\r\n  unescapeHTML: function() {\r\n    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');\r\n  }\r\n});\r\n\r\nString.prototype.gsub.prepareReplacement = function(replacement) {\r\n  if (Object.isFunction(replacement)) return replacement;\r\n  var template = new Template(replacement);\r\n  return function(match) { return template.evaluate(match) };\r\n};\r\n\r\nString.prototype.parseQuery = String.prototype.toQueryParams;\r\n\r\nObject.extend(String.prototype.escapeHTML, {\r\n  div:  document.createElement('div'),\r\n  text: document.createTextNode('')\r\n});\r\n\r\nwith (String.prototype.escapeHTML) div.appendChild(text);\r\n\r\nvar Template = Class.create({\r\n  initialize: function(template, pattern) {\r\n    this.template = template.toString();\r\n    this.pattern = pattern || Template.Pattern;\r\n  },\r\n\r\n  evaluate: function(object) {\r\n    if (Object.isFunction(object.toTemplateReplacements))\r\n      object = object.toTemplateReplacements();\r\n\r\n    return this.template.gsub(this.pattern, function(match) {\r\n      if (object == null) return '';\r\n\r\n      var before = match[1] || '';\r\n      if (before == '\\\\') return match[2];\r\n\r\n      var ctx = object, expr = match[3];\r\n      var pattern = /^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;\r\n      match = pattern.exec(expr);\r\n      if (match == null) return before;\r\n\r\n      while (match != null) {\r\n        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\\\\\]', ']') : match[1];\r\n        ctx = ctx[comp];\r\n        if (null == ctx || '' == match[3]) break;\r\n        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);\r\n        match = pattern.exec(expr);\r\n      }\r\n\r\n      return before + String.interpret(ctx);\r\n    });\r\n  }\r\n});\r\nTemplate.Pattern = /(^|.|\\r|\\n)(#\\{(.*?)\\})/;\r\n\r\nvar $break = { };\r\n\r\nvar Enumerable = {\r\n  each: function(iterator, context) {\r\n    var index = 0;\r\n    iterator = iterator.bind(context);\r\n    try {\r\n      this._each(function(value) {\r\n        iterator(value, index++);\r\n      });\r\n    } catch (e) {\r\n      if (e != $break) throw e;\r\n    }\r\n    return this;\r\n  },\r\n\r\n  eachSlice: function(number, iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var index = -number, slices = [], array = this.toArray();\r\n    while ((index += number) < array.length)\r\n      slices.push(array.slice(index, index+number));\r\n    return slices.collect(iterator, context);\r\n  },\r\n\r\n  all: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var result = true;\r\n    this.each(function(value, index) {\r\n      result = result && !!iterator(value, index);\r\n      if (!result) throw $break;\r\n    });\r\n    return result;\r\n  },\r\n\r\n  any: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var result = false;\r\n    this.each(function(value, index) {\r\n      if (result = !!iterator(value, index))\r\n        throw $break;\r\n    });\r\n    return result;\r\n  },\r\n\r\n  collect: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var results = [];\r\n    this.each(function(value, index) {\r\n      results.push(iterator(value, index));\r\n    });\r\n    return results;\r\n  },\r\n\r\n  detect: function(iterator, context) {\r\n    iterator = iterator.bind(context);\r\n    var result;\r\n    this.each(function(value, index) {\r\n      if (iterator(value, index)) {\r\n        result = value;\r\n        throw $break;\r\n      }\r\n    });\r\n    return result;\r\n  },\r\n\r\n  findAll: function(iterator, context) {\r\n    iterator = iterator.bind(context);\r\n    var results = [];\r\n    this.each(function(value, index) {\r\n      if (iterator(value, index))\r\n        results.push(value);\r\n    });\r\n    return results;\r\n  },\r\n\r\n  grep: function(filter, iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var results = [];\r\n\r\n    if (Object.isString(filter))\r\n      filter = new RegExp(filter);\r\n\r\n    this.each(function(value, index) {\r\n      if (filter.match(value))\r\n        results.push(iterator(value, index));\r\n    });\r\n    return results;\r\n  },\r\n\r\n  include: function(object) {\r\n    if (Object.isFunction(this.indexOf))\r\n      if (this.indexOf(object) != -1) return true;\r\n\r\n    var found = false;\r\n    this.each(function(value) {\r\n      if (value == object) {\r\n        found = true;\r\n        throw $break;\r\n      }\r\n    });\r\n    return found;\r\n  },\r\n\r\n  inGroupsOf: function(number, fillWith) {\r\n    fillWith = Object.isUndefined(fillWith) ? null : fillWith;\r\n    return this.eachSlice(number, function(slice) {\r\n      while(slice.length < number) slice.push(fillWith);\r\n      return slice;\r\n    });\r\n  },\r\n\r\n  inject: function(memo, iterator, context) {\r\n    iterator = iterator.bind(context);\r\n    this.each(function(value, index) {\r\n      memo = iterator(memo, value, index);\r\n    });\r\n    return memo;\r\n  },\r\n\r\n  invoke: function(method) {\r\n    var args = $A(arguments).slice(1);\r\n    return this.map(function(value) {\r\n      return value[method].apply(value, args);\r\n    });\r\n  },\r\n\r\n  max: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var result;\r\n    this.each(function(value, index) {\r\n      value = iterator(value, index);\r\n      if (result == null || value >= result)\r\n        result = value;\r\n    });\r\n    return result;\r\n  },\r\n\r\n  min: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var result;\r\n    this.each(function(value, index) {\r\n      value = iterator(value, index);\r\n      if (result == null || value < result)\r\n        result = value;\r\n    });\r\n    return result;\r\n  },\r\n\r\n  partition: function(iterator, context) {\r\n    iterator = iterator ? iterator.bind(context) : Prototype.K;\r\n    var trues = [], falses = [];\r\n    this.each(function(value, index) {\r\n      (iterator(value, index) ?\r\n        trues : falses).push(value);\r\n    });\r\n    return [trues, falses];\r\n  },\r\n\r\n  pluck: function(property) {\r\n    var results = [];\r\n    this.each(function(value) {\r\n      results.push(value[property]);\r\n    });\r\n    return results;\r\n  },\r\n\r\n  reject: function(iterator, context) {\r\n    iterator = iterator.bind(context);\r\n    var results = [];\r\n    this.each(function(value, index) {\r\n      if (!iterator(value, index))\r\n        results.push(value);\r\n    });\r\n    return results;\r\n  },\r\n\r\n  sortBy: function(iterator, context) {\r\n    iterator = iterator.bind(context);\r\n    return this.map(function(value, index) {\r\n      return {value: value, criteria: iterator(value, index)};\r\n    }).sort(function(left, right) {\r\n      var a = left.criteria, b = right.criteria;\r\n      return a < b ? -1 : a > b ? 1 : 0;\r\n    }).pluck('value');\r\n  },\r\n\r\n  toArray: function() {\r\n    return this.map();\r\n  },\r\n\r\n  zip: function() {\r\n    var iterator = Prototype.K, args = $A(arguments);\r\n    if (Object.isFunction(args.last()))\r\n      iterator = args.pop();\r\n\r\n    var collections = [this].concat(args).map($A);\r\n    return this.map(function(value, index) {\r\n      return iterator(collections.pluck(index));\r\n    });\r\n  },\r\n\r\n  size: function() {\r\n    return this.toArray().length;\r\n  },\r\n\r\n  inspect: function() {\r\n    return '#<Enumerable:' + this.toArray().inspect() + '>';\r\n  }\r\n};\r\n\r\nObject.extend(Enumerable, {\r\n  map:     Enumerable.collect,\r\n  find:    Enumerable.detect,\r\n  select:  Enumerable.findAll,\r\n  filter:  Enumerable.findAll,\r\n  member:  Enumerable.include,\r\n  entries: Enumerable.toArray,\r\n  every:   Enumerable.all,\r\n  some:    Enumerable.any\r\n});\r\nfunction $A(iterable) {\r\n  if (!iterable) return [];\r\n  if (iterable.toArray) return iterable.toArray();\r\n  var length = iterable.length || 0, results = new Array(length);\r\n  while (length--) results[length] = iterable[length];\r\n  return results;\r\n}\r\n\r\nif (Prototype.Browser.WebKit) {\r\n  $A = function(iterable) {\r\n    if (!iterable) return [];\r\n    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&\r\n        iterable.toArray) return iterable.toArray();\r\n    var length = iterable.length || 0, results = new Array(length);\r\n    while (length--) results[length] = iterable[length];\r\n    return results;\r\n  };\r\n}\r\n\r\nArray.from = $A;\r\n\r\nObject.extend(Array.prototype, Enumerable);\r\n\r\nif (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;\r\n\r\nObject.extend(Array.prototype, {\r\n  _each: function(iterator) {\r\n    for (var i = 0, length = this.length; i < length; i++)\r\n      iterator(this[i]);\r\n  },\r\n\r\n  clear: function() {\r\n    this.length = 0;\r\n    return this;\r\n  },\r\n\r\n  first: function() {\r\n    return this[0];\r\n  },\r\n\r\n  last: function() {\r\n    return this[this.length - 1];\r\n  },\r\n\r\n  compact: function() {\r\n    return this.select(function(value) {\r\n      return value != null;\r\n    });\r\n  },\r\n\r\n  flatten: function() {\r\n    return this.inject([], function(array, value) {\r\n      return array.concat(Object.isArray(value) ?\r\n        value.flatten() : [value]);\r\n    });\r\n  },\r\n\r\n  without: function() {\r\n    var values = $A(arguments);\r\n    return this.select(function(value) {\r\n      return !values.include(value);\r\n    });\r\n  },\r\n\r\n  reverse: function(inline) {\r\n    return (inline !== false ? this : this.toArray())._reverse();\r\n  },\r\n\r\n  reduce: function() {\r\n    return this.length > 1 ? this : this[0];\r\n  },\r\n\r\n  uniq: function(sorted) {\r\n    return this.inject([], function(array, value, index) {\r\n      if (0 == index || (sorted ? array.last() != value : !array.include(value)))\r\n        array.push(value);\r\n      return array;\r\n    });\r\n  },\r\n\r\n  intersect: function(array) {\r\n    return this.uniq().findAll(function(item) {\r\n      return array.detect(function(value) { return item === value });\r\n    });\r\n  },\r\n\r\n  clone: function() {\r\n    return [].concat(this);\r\n  },\r\n\r\n  size: function() {\r\n    return this.length;\r\n  },\r\n\r\n  inspect: function() {\r\n    return '[' + this.map(Object.inspect).join(', ') + ']';\r\n  },\r\n\r\n  toJSON: function() {\r\n    var results = [];\r\n    this.each(function(object) {\r\n      var value = Object.toJSON(object);\r\n      if (!Object.isUndefined(value)) results.push(value);\r\n    });\r\n    return '[' + results.join(', ') + ']';\r\n  }\r\n});\r\n\r\n// use native browser JS 1.6 implementation if available\r\nif (Object.isFunction(Array.prototype.forEach))\r\n  Array.prototype._each = Array.prototype.forEach;\r\n\r\nif (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {\r\n  i || (i = 0);\r\n  var length = this.length;\r\n  if (i < 0) i = length + i;\r\n  for (; i < length; i++)\r\n    if (this[i] === item) return i;\r\n  return -1;\r\n};\r\n\r\nif (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {\r\n  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;\r\n  var n = this.slice(0, i).reverse().indexOf(item);\r\n  return (n < 0) ? n : i - n - 1;\r\n};\r\n\r\nArray.prototype.toArray = Array.prototype.clone;\r\n\r\nfunction $w(string) {\r\n  if (!Object.isString(string)) return [];\r\n  string = string.strip();\r\n  return string ? string.split(/\\s+/) : [];\r\n}\r\n\r\nif (Prototype.Browser.Opera){\r\n  Array.prototype.concat = function() {\r\n    var array = [];\r\n    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);\r\n    for (var i = 0, length = arguments.length; i < length; i++) {\r\n      if (Object.isArray(arguments[i])) {\r\n        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)\r\n          array.push(arguments[i][j]);\r\n      } else {\r\n        array.push(arguments[i]);\r\n      }\r\n    }\r\n    return array;\r\n  };\r\n}\r\nObject.extend(Number.prototype, {\r\n  toColorPart: function() {\r\n    return this.toPaddedString(2, 16);\r\n  },\r\n\r\n  succ: function() {\r\n    return this + 1;\r\n  },\r\n\r\n  times: function(iterator) {\r\n    $R(0, this, true).each(iterator);\r\n    return this;\r\n  },\r\n\r\n  toPaddedString: function(length, radix) {\r\n    var string = this.toString(radix || 10);\r\n    return '0'.times(length - string.length) + string;\r\n  },\r\n\r\n  toJSON: function() {\r\n    return isFinite(this) ? this.toString() : 'null';\r\n  }\r\n});\r\n\r\n$w('abs round ceil floor').each(function(method){\r\n  Number.prototype[method] = Math[method].methodize();\r\n});\r\nfunction $H(object) {\r\n  return new Hash(object);\r\n};\r\n\r\nvar Hash = Class.create(Enumerable, (function() {\r\n\r\n  function toQueryPair(key, value) {\r\n    if (Object.isUndefined(value)) return key;\r\n    return key + '=' + encodeURIComponent(String.interpret(value));\r\n  }\r\n\r\n  return {\r\n    initialize: function(object) {\r\n      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);\r\n    },\r\n\r\n    _each: function(iterator) {\r\n      for (var key in this._object) {\r\n        var value = this._object[key], pair = [key, value];\r\n        pair.key = key;\r\n        pair.value = value;\r\n        iterator(pair);\r\n      }\r\n    },\r\n\r\n    set: function(key, value) {\r\n      return this._object[key] = value;\r\n    },\r\n\r\n    get: function(key) {\r\n      return this._object[key];\r\n    },\r\n\r\n    unset: function(key) {\r\n      var value = this._object[key];\r\n      delete this._object[key];\r\n      return value;\r\n    },\r\n\r\n    toObject: function() {\r\n      return Object.clone(this._object);\r\n    },\r\n\r\n    keys: function() {\r\n      return this.pluck('key');\r\n    },\r\n\r\n    values: function() {\r\n      return this.pluck('value');\r\n    },\r\n\r\n    index: function(value) {\r\n      var match = this.detect(function(pair) {\r\n        return pair.value === value;\r\n      });\r\n      return match && match.key;\r\n    },\r\n\r\n    merge: function(object) {\r\n      return this.clone().update(object);\r\n    },\r\n\r\n    update: function(object) {\r\n      return new Hash(object).inject(this, function(result, pair) {\r\n        result.set(pair.key, pair.value);\r\n        return result;\r\n      });\r\n    },\r\n\r\n    toQueryString: function() {\r\n      return this.map(function(pair) {\r\n        var key = encodeURIComponent(pair.key), values = pair.value;\r\n\r\n        if (values && typeof values == 'object') {\r\n          if (Object.isArray(values))\r\n            return values.map(toQueryPair.curry(key)).join('&');\r\n        }\r\n        return toQueryPair(key, values);\r\n      }).join('&');\r\n    },\r\n\r\n    inspect: function() {\r\n      return '#<Hash:{' + this.map(function(pair) {\r\n        return pair.map(Object.inspect).join(': ');\r\n      }).join(', ') + '}>';\r\n    },\r\n\r\n    toJSON: function() {\r\n      return Object.toJSON(this.toObject());\r\n    },\r\n\r\n    clone: function() {\r\n      return new Hash(this);\r\n    }\r\n  }\r\n})());\r\n\r\nHash.prototype.toTemplateReplacements = Hash.prototype.toObject;\r\nHash.from = $H;\r\nvar ObjectRange = Class.create(Enumerable, {\r\n  initialize: function(start, end, exclusive) {\r\n    this.start = start;\r\n    this.end = end;\r\n    this.exclusive = exclusive;\r\n  },\r\n\r\n  _each: function(iterator) {\r\n    var value = this.start;\r\n    while (this.include(value)) {\r\n      iterator(value);\r\n      value = value.succ();\r\n    }\r\n  },\r\n\r\n  include: function(value) {\r\n    if (value < this.start)\r\n      return false;\r\n    if (this.exclusive)\r\n      return value < this.end;\r\n    return value <= this.end;\r\n  }\r\n});\r\n\r\nvar $R = function(start, end, exclusive) {\r\n  return new ObjectRange(start, end, exclusive);\r\n};\r\n\r\nvar Ajax = {\r\n  getTransport: function() {\r\n    return Try.these(\r\n      function() {return new XMLHttpRequest()},\r\n      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\r\n      function() {return new ActiveXObject('Microsoft.XMLHTTP')}\r\n    ) || false;\r\n  },\r\n\r\n  activeRequestCount: 0\r\n};\r\n\r\nAjax.Responders = {\r\n  responders: [],\r\n\r\n  _each: function(iterator) {\r\n    this.responders._each(iterator);\r\n  },\r\n\r\n  register: function(responder) {\r\n    if (!this.include(responder))\r\n      this.responders.push(responder);\r\n  },\r\n\r\n  unregister: function(responder) {\r\n    this.responders = this.responders.without(responder);\r\n  },\r\n\r\n  dispatch: function(callback, request, transport, json) {\r\n    this.each(function(responder) {\r\n      if (Object.isFunction(responder[callback])) {\r\n        try {\r\n          responder[callback].apply(responder, [request, transport, json]);\r\n        } catch (e) { }\r\n      }\r\n    });\r\n  }\r\n};\r\n\r\nObject.extend(Ajax.Responders, Enumerable);\r\n\r\nAjax.Responders.register({\r\n  onCreate:   function() { Ajax.activeRequestCount++ },\r\n  onComplete: function() { Ajax.activeRequestCount-- }\r\n});\r\n\r\nAjax.Base = Class.create({\r\n  initialize: function(options) {\r\n    this.options = {\r\n      method:       'post',\r\n      asynchronous: true,\r\n      contentType:  'application/x-www-form-urlencoded',\r\n      encoding:     'UTF-8',\r\n      parameters:   '',\r\n      evalJSON:     true,\r\n      evalJS:       true\r\n    };\r\n    Object.extend(this.options, options || { });\r\n\r\n    this.options.method = this.options.method.toLowerCase();\r\n\r\n    if (Object.isString(this.options.parameters))\r\n      this.options.parameters = this.options.parameters.toQueryParams();\r\n    else if (Object.isHash(this.options.parameters))\r\n      this.options.parameters = this.options.parameters.toObject();\r\n  }\r\n});\r\n\r\nAjax.Request = Class.create(Ajax.Base, {\r\n  _complete: false,\r\n\r\n  initialize: function($super, url, options) {\r\n    $super(options);\r\n    this.transport = Ajax.getTransport();\r\n    this.request(url);\r\n  },\r\n\r\n  request: function(url) {\r\n    this.url = url;\r\n    this.method = this.options.method;\r\n    var params = Object.clone(this.options.parameters);\r\n\r\n    if (!['get', 'post'].include(this.method)) {\r\n      // simulate other verbs over post\r\n      params['_method'] = this.method;\r\n      this.method = 'post';\r\n    }\r\n\r\n    this.parameters = params;\r\n\r\n    if (params = Object.toQueryString(params)) {\r\n      // when GET, append parameters to URL\r\n      if (this.method == 'get')\r\n        this.url += (this.url.include('?') ? '&' : '?') + params;\r\n      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))\r\n        params += '&_=';\r\n    }\r\n\r\n    try {\r\n      var response = new Ajax.Response(this);\r\n      if (this.options.onCreate) this.options.onCreate(response);\r\n      Ajax.Responders.dispatch('onCreate', this, response);\r\n\r\n      this.transport.open(this.method.toUpperCase(), this.url,\r\n        this.options.asynchronous);\r\n\r\n      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);\r\n\r\n      this.transport.onreadystatechange = this.onStateChange.bind(this);\r\n      this.setRequestHeaders();\r\n\r\n      this.body = this.method == 'post' ? (this.options.postBody || params) : null;\r\n      this.transport.send(this.body);\r\n\r\n      /* Force Firefox to handle ready state 4 for synchronous requests */\r\n      if (!this.options.asynchronous && this.transport.overrideMimeType)\r\n        this.onStateChange();\r\n\r\n    }\r\n    catch (e) {\r\n      this.dispatchException(e);\r\n    }\r\n  },\r\n\r\n  onStateChange: function() {\r\n    var readyState = this.transport.readyState;\r\n    if (readyState > 1 && !((readyState == 4) && this._complete))\r\n      this.respondToReadyState(this.transport.readyState);\r\n  },\r\n\r\n  setRequestHeaders: function() {\r\n    var headers = {\r\n      'X-Requested-With': 'XMLHttpRequest',\r\n      'X-Prototype-Version': Prototype.Version,\r\n      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'\r\n    };\r\n\r\n    if (this.method == 'post') {\r\n      headers['Content-type'] = this.options.contentType +\r\n        (this.options.encoding ? '; charset=' + this.options.encoding : '');\r\n\r\n      /* Force \"Connection: close\" for older Mozilla browsers to work\r\n       * around a bug where XMLHttpRequest sends an incorrect\r\n       * Content-length header. See Mozilla Bugzilla #246651.\r\n       */\r\n      if (this.transport.overrideMimeType &&\r\n          (navigator.userAgent.match(/Gecko\\/(\\d{4})/) || [0,2005])[1] < 2005)\r\n            headers['Connection'] = 'close';\r\n    }\r\n\r\n    // user-defined headers\r\n    if (typeof this.options.requestHeaders == 'object') {\r\n      var extras = this.options.requestHeaders;\r\n\r\n      if (Object.isFunction(extras.push))\r\n        for (var i = 0, length = extras.length; i < length; i += 2)\r\n          headers[extras[i]] = extras[i+1];\r\n      else\r\n        $H(extras).each(function(pair) { headers[pair.key] = pair.value });\r\n    }\r\n\r\n    for (var name in headers)\r\n      this.transport.setRequestHeader(name, headers[name]);\r\n  },\r\n\r\n  success: function() {\r\n    var status = this.getStatus();\r\n    return !status || (status >= 200 && status < 300);\r\n  },\r\n\r\n  getStatus: function() {\r\n    try {\r\n      return this.transport.status || 0;\r\n    } catch (e) { return 0 }\r\n  },\r\n\r\n  respondToReadyState: function(readyState) {\r\n    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);\r\n\r\n    if (state == 'Complete') {\r\n      try {\r\n        this._complete = true;\r\n        (this.options['on' + response.status]\r\n         || this.options['on' + (this.success() ? 'Success' : 'Failure')]\r\n         || Prototype.emptyFunction)(response, response.headerJSON);\r\n      } catch (e) {\r\n        this.dispatchException(e);\r\n      }\r\n\r\n      var contentType = response.getHeader('Content-type');\r\n      if (this.options.evalJS == 'force'\r\n          || (this.options.evalJS && this.isSameOrigin() && contentType\r\n          && contentType.match(/^\\s*(text|application)\\/(x-)?(java|ecma)script(;.*)?\\s*$/i)))\r\n        this.evalResponse();\r\n    }\r\n\r\n    try {\r\n      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);\r\n      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);\r\n    } catch (e) {\r\n      this.dispatchException(e);\r\n    }\r\n\r\n    if (state == 'Complete') {\r\n      // avoid memory leak in MSIE: clean up\r\n      this.transport.onreadystatechange = Prototype.emptyFunction;\r\n    }\r\n  },\r\n\r\n  isSameOrigin: function() {\r\n    var m = this.url.match(/^\\s*https?:\\/\\/[^\\/]*/);\r\n    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({\r\n      protocol: location.protocol,\r\n      domain: document.domain,\r\n      port: location.port ? ':' + location.port : ''\r\n    }));\r\n  },\r\n\r\n  getHeader: function(name) {\r\n    try {\r\n      return this.transport.getResponseHeader(name) || null;\r\n    } catch (e) { return null }\r\n  },\r\n\r\n  evalResponse: function() {\r\n    try {\r\n      return eval((this.transport.responseText || '').unfilterJSON());\r\n    } catch (e) {\r\n      this.dispatchException(e);\r\n    }\r\n  },\r\n\r\n  dispatchException: function(exception) {\r\n    (this.options.onException || Prototype.emptyFunction)(this, exception);\r\n    Ajax.Responders.dispatch('onException', this, exception);\r\n  }\r\n});\r\n\r\nAjax.Request.Events =\r\n  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\r\n\r\nAjax.Response = Class.create({\r\n  initialize: function(request){\r\n    this.request = request;\r\n    var transport  = this.transport  = request.transport,\r\n        readyState = this.readyState = transport.readyState;\r\n\r\n    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {\r\n      this.status       = this.getStatus();\r\n      this.statusText   = this.getStatusText();\r\n      this.responseText = String.interpret(transport.responseText);\r\n      this.headerJSON   = this._getHeaderJSON();\r\n    }\r\n\r\n    if(readyState == 4) {\r\n      var xml = transport.responseXML;\r\n      this.responseXML  = Object.isUndefined(xml) ? null : xml;\r\n      this.responseJSON = this._getResponseJSON();\r\n    }\r\n  },\r\n\r\n  status:      0,\r\n  statusText: '',\r\n\r\n  getStatus: Ajax.Request.prototype.getStatus,\r\n\r\n  getStatusText: function() {\r\n    try {\r\n      return this.transport.statusText || '';\r\n    } catch (e) { return '' }\r\n  },\r\n\r\n  getHeader: Ajax.Request.prototype.getHeader,\r\n\r\n  getAllHeaders: function() {\r\n    try {\r\n      return this.getAllResponseHeaders();\r\n    } catch (e) { return null }\r\n  },\r\n\r\n  getResponseHeader: function(name) {\r\n    return this.transport.getResponseHeader(name);\r\n  },\r\n\r\n  getAllResponseHeaders: function() {\r\n    return this.transport.getAllResponseHeaders();\r\n  },\r\n\r\n  _getHeaderJSON: function() {\r\n    var json = this.getHeader('X-JSON');\r\n    if (!json) return null;\r\n    json = decodeURIComponent(escape(json));\r\n    try {\r\n      return json.evalJSON(this.request.options.sanitizeJSON ||\r\n        !this.request.isSameOrigin());\r\n    } catch (e) {\r\n      this.request.dispatchException(e);\r\n    }\r\n  },\r\n\r\n  _getResponseJSON: function() {\r\n    var options = this.request.options;\r\n    if (!options.evalJSON || (options.evalJSON != 'force' &&\r\n      !(this.getHeader('Content-type') || '').include('application/json')) ||\r\n        this.responseText.blank())\r\n          return null;\r\n    try {\r\n      return this.responseText.evalJSON(options.sanitizeJSON ||\r\n        !this.request.isSameOrigin());\r\n    } catch (e) {\r\n      this.request.dispatchException(e);\r\n    }\r\n  }\r\n});\r\n\r\nAjax.Updater = Class.create(Ajax.Request, {\r\n  initialize: function($super, container, url, options) {\r\n    this.container = {\r\n      success: (container.success || container),\r\n      failure: (container.failure || (container.success ? null : container))\r\n    };\r\n\r\n    options = Object.clone(options);\r\n    var onComplete = options.onComplete;\r\n    options.onComplete = (function(response, json) {\r\n      this.updateContent(response.responseText);\r\n      if (Object.isFunction(onComplete)) onComplete(response, json);\r\n    }).bind(this);\r\n\r\n    $super(url, options);\r\n  },\r\n\r\n  updateContent: function(responseText) {\r\n    var receiver = this.container[this.success() ? 'success' : 'failure'],\r\n        options = this.options;\r\n\r\n    if (!options.evalScripts) responseText = responseText.stripScripts();\r\n\r\n    if (receiver = $(receiver)) {\r\n      if (options.insertion) {\r\n        if (Object.isString(options.insertion)) {\r\n          var insertion = { }; insertion[options.insertion] = responseText;\r\n          receiver.insert(insertion);\r\n        }\r\n        else options.insertion(receiver, responseText);\r\n      }\r\n      else receiver.update(responseText);\r\n    }\r\n  }\r\n});\r\n\r\nAjax.PeriodicalUpdater = Class.create(Ajax.Base, {\r\n  initialize: function($super, container, url, options) {\r\n    $super(options);\r\n    this.onComplete = this.options.onComplete;\r\n\r\n    this.frequency = (this.options.frequency || 2);\r\n    this.decay = (this.options.decay || 1);\r\n\r\n    this.updater = { };\r\n    this.container = container;\r\n    this.url = url;\r\n\r\n    this.start();\r\n  },\r\n\r\n  start: function() {\r\n    this.options.onComplete = this.updateComplete.bind(this);\r\n    this.onTimerEvent();\r\n  },\r\n\r\n  stop: function() {\r\n    this.updater.options.onComplete = undefined;\r\n    clearTimeout(this.timer);\r\n    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\r\n  },\r\n\r\n  updateComplete: function(response) {\r\n    if (this.options.decay) {\r\n      this.decay = (response.responseText == this.lastText ?\r\n        this.decay * this.options.decay : 1);\r\n\r\n      this.lastText = response.responseText;\r\n    }\r\n    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);\r\n  },\r\n\r\n  onTimerEvent: function() {\r\n    this.updater = new Ajax.Updater(this.container, this.url, this.options);\r\n  }\r\n});\r\nfunction $(element) {\r\n  if (arguments.length > 1) {\r\n    for (var i = 0, elements = [], length = arguments.length; i < length; i++)\r\n      elements.push($(arguments[i]));\r\n    return elements;\r\n  }\r\n  if (Object.isString(element))\r\n    element = document.getElementById(element);\r\n  return Element.extend(element);\r\n}\r\n\r\nif (Prototype.BrowserFeatures.XPath) {\r\n  document._getElementsByXPath = function(expression, parentElement) {\r\n    var results = [];\r\n    var query = document.evaluate(expression, $(parentElement) || document,\r\n      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\r\n    for (var i = 0, length = query.snapshotLength; i < length; i++)\r\n      results.push(Element.extend(query.snapshotItem(i)));\r\n    return results;\r\n  };\r\n}\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nif (!window.Node) var Node = { };\r\n\r\nif (!Node.ELEMENT_NODE) {\r\n  // DOM level 2 ECMAScript Language Binding\r\n  Object.extend(Node, {\r\n    ELEMENT_NODE: 1,\r\n    ATTRIBUTE_NODE: 2,\r\n    TEXT_NODE: 3,\r\n    CDATA_SECTION_NODE: 4,\r\n    ENTITY_REFERENCE_NODE: 5,\r\n    ENTITY_NODE: 6,\r\n    PROCESSING_INSTRUCTION_NODE: 7,\r\n    COMMENT_NODE: 8,\r\n    DOCUMENT_NODE: 9,\r\n    DOCUMENT_TYPE_NODE: 10,\r\n    DOCUMENT_FRAGMENT_NODE: 11,\r\n    NOTATION_NODE: 12\r\n  });\r\n}\r\n\r\n(function() {\r\n  var element = this.Element;\r\n  this.Element = function(tagName, attributes) {\r\n    attributes = attributes || { };\r\n    tagName = tagName.toLowerCase();\r\n    var cache = Element.cache;\r\n    if (Prototype.Browser.IE && attributes.name) {\r\n      tagName = '<' + tagName + ' name=\"' + attributes.name + '\">';\r\n      delete attributes.name;\r\n      return Element.writeAttribute(document.createElement(tagName), attributes);\r\n    }\r\n    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));\r\n    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);\r\n  };\r\n  Object.extend(this.Element, element || { });\r\n}).call(window);\r\n\r\nElement.cache = { };\r\n\r\nElement.Methods = {\r\n  visible: function(element) {\r\n    return $(element).style.display != 'none';\r\n  },\r\n\r\n  toggle: function(element) {\r\n    element = $(element);\r\n    Element[Element.visible(element) ? 'hide' : 'show'](element);\r\n    return element;\r\n  },\r\n\r\n  hide: function(element) {\r\n    $(element).style.display = 'none';\r\n    return element;\r\n  },\r\n\r\n  show: function(element) {\r\n    $(element).style.display = '';\r\n    return element;\r\n  },\r\n\r\n  remove: function(element) {\r\n    element = $(element);\r\n    element.parentNode.removeChild(element);\r\n    return element;\r\n  },\r\n\r\n  update: function(element, content) {\r\n    element = $(element);\r\n    if (content && content.toElement) content = content.toElement();\r\n    if (Object.isElement(content)) return element.update().insert(content);\r\n    content = Object.toHTML(content);\r\n    element.innerHTML = content.stripScripts();\r\n    content.evalScripts.bind(content).defer();\r\n    return element;\r\n  },\r\n\r\n  replace: function(element, content) {\r\n    element = $(element);\r\n    if (content && content.toElement) content = content.toElement();\r\n    else if (!Object.isElement(content)) {\r\n      content = Object.toHTML(content);\r\n      var range = element.ownerDocument.createRange();\r\n      range.selectNode(element);\r\n      content.evalScripts.bind(content).defer();\r\n      content = range.createContextualFragment(content.stripScripts());\r\n    }\r\n    element.parentNode.replaceChild(content, element);\r\n    return element;\r\n  },\r\n\r\n  insert: function(element, insertions) {\r\n    element = $(element);\r\n\r\n    if (Object.isString(insertions) || Object.isNumber(insertions) ||\r\n        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))\r\n          insertions = {bottom:insertions};\r\n\r\n    var content, insert, tagName, childNodes;\r\n\r\n    for (var position in insertions) {\r\n      content  = insertions[position];\r\n      position = position.toLowerCase();\r\n      insert = Element._insertionTranslations[position];\r\n\r\n      if (content && content.toElement) content = content.toElement();\r\n      if (Object.isElement(content)) {\r\n        insert(element, content);\r\n        continue;\r\n      }\r\n\r\n      content = Object.toHTML(content);\r\n\r\n      tagName = ((position == 'before' || position == 'after')\r\n        ? element.parentNode : element).tagName.toUpperCase();\r\n\r\n      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\r\n\r\n      if (position == 'top' || position == 'after') childNodes.reverse();\r\n      childNodes.each(insert.curry(element));\r\n\r\n      content.evalScripts.bind(content).defer();\r\n    }\r\n\r\n    return element;\r\n  },\r\n\r\n  wrap: function(element, wrapper, attributes) {\r\n    element = $(element);\r\n    if (Object.isElement(wrapper))\r\n      $(wrapper).writeAttribute(attributes || { });\r\n    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);\r\n    else wrapper = new Element('div', wrapper);\r\n    if (element.parentNode)\r\n      element.parentNode.replaceChild(wrapper, element);\r\n    wrapper.appendChild(element);\r\n    return wrapper;\r\n  },\r\n\r\n  inspect: function(element) {\r\n    element = $(element);\r\n    var result = '<' + element.tagName.toLowerCase();\r\n    $H({'id': 'id', 'className': 'class'}).each(function(pair) {\r\n      var property = pair.first(), attribute = pair.last();\r\n      var value = (element[property] || '').toString();\r\n      if (value) result += ' ' + attribute + '=' + value.inspect(true);\r\n    });\r\n    return result + '>';\r\n  },\r\n\r\n  recursivelyCollect: function(element, property) {\r\n    element = $(element);\r\n    var elements = [];\r\n    while (element = element[property])\r\n      if (element.nodeType == 1)\r\n        elements.push(Element.extend(element));\r\n    return elements;\r\n  },\r\n\r\n  ancestors: function(element) {\r\n    return $(element).recursivelyCollect('parentNode');\r\n  },\r\n\r\n  descendants: function(element) {\r\n    return $(element).select(\"*\");\r\n  },\r\n\r\n  firstDescendant: function(element) {\r\n    element = $(element).firstChild;\r\n    while (element && element.nodeType != 1) element = element.nextSibling;\r\n    return $(element);\r\n  },\r\n\r\n  immediateDescendants: function(element) {\r\n    if (!(element = $(element).firstChild)) return [];\r\n    while (element && element.nodeType != 1) element = element.nextSibling;\r\n    if (element) return [element].concat($(element).nextSiblings());\r\n    return [];\r\n  },\r\n\r\n  previousSiblings: function(element) {\r\n    return $(element).recursivelyCollect('previousSibling');\r\n  },\r\n\r\n  nextSiblings: function(element) {\r\n    return $(element).recursivelyCollect('nextSibling');\r\n  },\r\n\r\n  siblings: function(element) {\r\n    element = $(element);\r\n    return element.previousSiblings().reverse().concat(element.nextSiblings());\r\n  },\r\n\r\n  match: function(element, selector) {\r\n    if (Object.isString(selector))\r\n      selector = new Selector(selector);\r\n    return selector.match($(element));\r\n  },\r\n\r\n  up: function(element, expression, index) {\r\n    element = $(element);\r\n    if (arguments.length == 1) return $(element.parentNode);\r\n    var ancestors = element.ancestors();\r\n    return Object.isNumber(expression) ? ancestors[expression] :\r\n      Selector.findElement(ancestors, expression, index);\r\n  },\r\n\r\n  down: function(element, expression, index) {\r\n    element = $(element);\r\n    if (arguments.length == 1) return element.firstDescendant();\r\n    return Object.isNumber(expression) ? element.descendants()[expression] :\r\n      element.select(expression)[index || 0];\r\n  },\r\n\r\n  previous: function(element, expression, index) {\r\n    element = $(element);\r\n    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));\r\n    var previousSiblings = element.previousSiblings();\r\n    return Object.isNumber(expression) ? previousSiblings[expression] :\r\n      Selector.findElement(previousSiblings, expression, index);\r\n  },\r\n\r\n  next: function(element, expression, index) {\r\n    element = $(element);\r\n    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));\r\n    var nextSiblings = element.nextSiblings();\r\n    return Object.isNumber(expression) ? nextSiblings[expression] :\r\n      Selector.findElement(nextSiblings, expression, index);\r\n  },\r\n\r\n  select: function() {\r\n    var args = $A(arguments), element = $(args.shift());\r\n    return Selector.findChildElements(element, args);\r\n  },\r\n\r\n  adjacent: function() {\r\n    var args = $A(arguments), element = $(args.shift());\r\n    return Selector.findChildElements(element.parentNode, args).without(element);\r\n  },\r\n\r\n  identify: function(element) {\r\n    element = $(element);\r\n    var id = element.readAttribute('id'), self = arguments.callee;\r\n    if (id) return id;\r\n    do { id = 'anonymous_element_' + self.counter++ } while ($(id));\r\n    element.writeAttribute('id', id);\r\n    return id;\r\n  },\r\n\r\n  readAttribute: function(element, name) {\r\n    element = $(element);\r\n    if (Prototype.Browser.IE) {\r\n      var t = Element._attributeTranslations.read;\r\n      if (t.values[name]) return t.values[name](element, name);\r\n      if (t.names[name]) name = t.names[name];\r\n      if (name.include(':')) {\r\n        return (!element.attributes || !element.attributes[name]) ? null :\r\n         element.attributes[name].value;\r\n      }\r\n    }\r\n    return element.getAttribute(name);\r\n  },\r\n\r\n  writeAttribute: function(element, name, value) {\r\n    element = $(element);\r\n    var attributes = { }, t = Element._attributeTranslations.write;\r\n\r\n    if (typeof name == 'object') attributes = name;\r\n    else attributes[name] = Object.isUndefined(value) ? true : value;\r\n\r\n    for (var attr in attributes) {\r\n      name = t.names[attr] || attr;\r\n      value = attributes[attr];\r\n      if (t.values[attr]) name = t.values[attr](element, value);\r\n      if (value === false || value === null)\r\n        element.removeAttribute(name);\r\n      else if (value === true)\r\n        element.setAttribute(name, name);\r\n      else element.setAttribute(name, value);\r\n    }\r\n    return element;\r\n  },\r\n\r\n  getHeight: function(element) {\r\n    return $(element).getDimensions().height;\r\n  },\r\n\r\n  getWidth: function(element) {\r\n    return $(element).getDimensions().width;\r\n  },\r\n\r\n  classNames: function(element) {\r\n    return new Element.ClassNames(element);\r\n  },\r\n\r\n  hasClassName: function(element, className) {\r\n    if (!(element = $(element))) return;\r\n    var elementClassName = element.className;\r\n    return (elementClassName.length > 0 && (elementClassName == className ||\r\n      new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\").test(elementClassName)));\r\n  },\r\n\r\n  addClassName: function(element, className) {\r\n    if (!(element = $(element))) return;\r\n    if (!element.hasClassName(className))\r\n      element.className += (element.className ? ' ' : '') + className;\r\n    return element;\r\n  },\r\n\r\n  removeClassName: function(element, className) {\r\n    if (!(element = $(element))) return;\r\n    element.className = element.className.replace(\r\n      new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), ' ').strip();\r\n    return element;\r\n  },\r\n\r\n  toggleClassName: function(element, className) {\r\n    if (!(element = $(element))) return;\r\n    return element[element.hasClassName(className) ?\r\n      'removeClassName' : 'addClassName'](className);\r\n  },\r\n\r\n  // removes whitespace-only text node children\r\n  cleanWhitespace: function(element) {\r\n    element = $(element);\r\n    var node = element.firstChild;\r\n    while (node) {\r\n      var nextNode = node.nextSibling;\r\n      if (node.nodeType == 3 && !/\\S/.test(node.nodeValue))\r\n        element.removeChild(node);\r\n      node = nextNode;\r\n    }\r\n    return element;\r\n  },\r\n\r\n  empty: function(element) {\r\n    return $(element).innerHTML.blank();\r\n  },\r\n\r\n  descendantOf: function(element, ancestor) {\r\n    element = $(element), ancestor = $(ancestor);\r\n    var originalAncestor = ancestor;\r\n\r\n    if (element.compareDocumentPosition)\r\n      return (element.compareDocumentPosition(ancestor) & 8) === 8;\r\n\r\n    if (element.sourceIndex && !Prototype.Browser.Opera) {\r\n      var e = element.sourceIndex, a = ancestor.sourceIndex,\r\n       nextAncestor = ancestor.nextSibling;\r\n      if (!nextAncestor) {\r\n        do { ancestor = ancestor.parentNode; }\r\n        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);\r\n      }\r\n      if (nextAncestor && nextAncestor.sourceIndex)\r\n       return (e > a && e < nextAncestor.sourceIndex);\r\n    }\r\n\r\n    while (element = element.parentNode)\r\n      if (element == originalAncestor) return true;\r\n    return false;\r\n  },\r\n\r\n  scrollTo: function(element) {\r\n    element = $(element);\r\n    var pos = element.cumulativeOffset();\r\n    window.scrollTo(pos[0], pos[1]);\r\n    return element;\r\n  },\r\n\r\n  getStyle: function(element, style) {\r\n    element = $(element);\r\n    style = style == 'float' ? 'cssFloat' : style.camelize();\r\n    var value = element.style[style];\r\n    if (!value) {\r\n      var css = document.defaultView.getComputedStyle(element, null);\r\n      value = css ? css[style] : null;\r\n    }\r\n    if (style == 'opacity') return value ? parseFloat(value) : 1.0;\r\n    return value == 'auto' ? null : value;\r\n  },\r\n\r\n  getOpacity: function(element) {\r\n    return $(element).getStyle('opacity');\r\n  },\r\n\r\n  setStyle: function(element, styles) {\r\n    element = $(element);\r\n    var elementStyle = element.style, match;\r\n    if (Object.isString(styles)) {\r\n      element.style.cssText += ';' + styles;\r\n      return styles.include('opacity') ?\r\n        element.setOpacity(styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]) : element;\r\n    }\r\n    for (var property in styles)\r\n      if (property == 'opacity') element.setOpacity(styles[property]);\r\n      else\r\n        elementStyle[(property == 'float' || property == 'cssFloat') ?\r\n          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :\r\n            property] = styles[property];\r\n\r\n    return element;\r\n  },\r\n\r\n  setOpacity: function(element, value) {\r\n    element = $(element);\r\n    element.style.opacity = (value == 1 || value === '') ? '' :\r\n      (value < 0.00001) ? 0 : value;\r\n    return element;\r\n  },\r\n\r\n  getDimensions: function(element) {\r\n    element = $(element);\r\n    var display = $(element).getStyle('display');\r\n    if (display != 'none' && display != null) // Safari bug\r\n      return {width: element.offsetWidth, height: element.offsetHeight};\r\n\r\n    // All *Width and *Height properties give 0 on elements with display none,\r\n    // so enable the element temporarily\r\n    var els = element.style;\r\n    var originalVisibility = els.visibility;\r\n    var originalPosition = els.position;\r\n    var originalDisplay = els.display;\r\n    els.visibility = 'hidden';\r\n    els.position = 'absolute';\r\n    els.display = 'block';\r\n    var originalWidth = element.clientWidth;\r\n    var originalHeight = element.clientHeight;\r\n    els.display = originalDisplay;\r\n    els.position = originalPosition;\r\n    els.visibility = originalVisibility;\r\n    return {width: originalWidth, height: originalHeight};\r\n  },\r\n\r\n  makePositioned: function(element) {\r\n    element = $(element);\r\n    var pos = Element.getStyle(element, 'position');\r\n    if (pos == 'static' || !pos) {\r\n      element._madePositioned = true;\r\n      element.style.position = 'relative';\r\n      // Opera returns the offset relative to the positioning context, when an\r\n      // element is position relative but top and left have not been defined\r\n      if (window.opera) {\r\n        element.style.top = 0;\r\n        element.style.left = 0;\r\n      }\r\n    }\r\n    return element;\r\n  },\r\n\r\n  undoPositioned: function(element) {\r\n    element = $(element);\r\n    if (element._madePositioned) {\r\n      element._madePositioned = undefined;\r\n      element.style.position =\r\n        element.style.top =\r\n        element.style.left =\r\n        element.style.bottom =\r\n        element.style.right = '';\r\n    }\r\n    return element;\r\n  },\r\n\r\n  makeClipping: function(element) {\r\n    element = $(element);\r\n    if (element._overflow) return element;\r\n    element._overflow = Element.getStyle(element, 'overflow') || 'auto';\r\n    if (element._overflow !== 'hidden')\r\n      element.style.overflow = 'hidden';\r\n    return element;\r\n  },\r\n\r\n  undoClipping: function(element) {\r\n    element = $(element);\r\n    if (!element._overflow) return element;\r\n    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;\r\n    element._overflow = null;\r\n    return element;\r\n  },\r\n\r\n  cumulativeOffset: function(element) {\r\n    var valueT = 0, valueL = 0;\r\n    do {\r\n      valueT += element.offsetTop  || 0;\r\n      valueL += element.offsetLeft || 0;\r\n      element = element.offsetParent;\r\n    } while (element);\r\n    return Element._returnOffset(valueL, valueT);\r\n  },\r\n\r\n  positionedOffset: function(element) {\r\n    var valueT = 0, valueL = 0;\r\n    do {\r\n      valueT += element.offsetTop  || 0;\r\n      valueL += element.offsetLeft || 0;\r\n      element = element.offsetParent;\r\n      if (element) {\r\n        if (element.tagName == 'BODY') break;\r\n        var p = Element.getStyle(element, 'position');\r\n        if (p !== 'static') break;\r\n      }\r\n    } while (element);\r\n    return Element._returnOffset(valueL, valueT);\r\n  },\r\n\r\n  absolutize: function(element) {\r\n    element = $(element);\r\n    if (element.getStyle('position') == 'absolute') return;\r\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\r\n\r\n    var offsets = element.positionedOffset();\r\n    var top     = offsets[1];\r\n    var left    = offsets[0];\r\n    var width   = element.clientWidth;\r\n    var height  = element.clientHeight;\r\n\r\n    element._originalLeft   = left - parseFloat(element.style.left  || 0);\r\n    element._originalTop    = top  - parseFloat(element.style.top || 0);\r\n    element._originalWidth  = element.style.width;\r\n    element._originalHeight = element.style.height;\r\n\r\n    element.style.position = 'absolute';\r\n    element.style.top    = top + 'px';\r\n    element.style.left   = left + 'px';\r\n    element.style.width  = width + 'px';\r\n    element.style.height = height + 'px';\r\n    return element;\r\n  },\r\n\r\n  relativize: function(element) {\r\n    element = $(element);\r\n    if (element.getStyle('position') == 'relative') return;\r\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\r\n\r\n    element.style.position = 'relative';\r\n    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);\r\n    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);\r\n\r\n    element.style.top    = top + 'px';\r\n    element.style.left   = left + 'px';\r\n    element.style.height = element._originalHeight;\r\n    element.style.width  = element._originalWidth;\r\n    return element;\r\n  },\r\n\r\n  cumulativeScrollOffset: function(element) {\r\n    var valueT = 0, valueL = 0;\r\n    do {\r\n      valueT += element.scrollTop  || 0;\r\n      valueL += element.scrollLeft || 0;\r\n      element = element.parentNode;\r\n    } while (element);\r\n    return Element._returnOffset(valueL, valueT);\r\n  },\r\n\r\n  getOffsetParent: function(element) {\r\n    if (element.offsetParent) return $(element.offsetParent);\r\n    if (element == document.body) return $(element);\r\n\r\n    while ((element = element.parentNode) && element != document.body)\r\n      if (Element.getStyle(element, 'position') != 'static')\r\n        return $(element);\r\n\r\n    return $(document.body);\r\n  },\r\n\r\n  viewportOffset: function(forElement) {\r\n    var valueT = 0, valueL = 0;\r\n\r\n    var element = forElement;\r\n    do {\r\n      valueT += element.offsetTop  || 0;\r\n      valueL += element.offsetLeft || 0;\r\n\r\n      // Safari fix\r\n      if (element.offsetParent == document.body &&\r\n        Element.getStyle(element, 'position') == 'absolute') break;\r\n\r\n    } while (element = element.offsetParent);\r\n\r\n    element = forElement;\r\n    do {\r\n      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {\r\n        valueT -= element.scrollTop  || 0;\r\n        valueL -= element.scrollLeft || 0;\r\n      }\r\n    } while (element = element.parentNode);\r\n\r\n    return Element._returnOffset(valueL, valueT);\r\n  },\r\n\r\n  clonePosition: function(element, source) {\r\n    var options = Object.extend({\r\n      setLeft:    true,\r\n      setTop:     true,\r\n      setWidth:   true,\r\n      setHeight:  true,\r\n      offsetTop:  0,\r\n      offsetLeft: 0\r\n    }, arguments[2] || { });\r\n\r\n    // find page position of source\r\n    source = $(source);\r\n    var p = source.viewportOffset();\r\n\r\n    // find coordinate system to use\r\n    element = $(element);\r\n    var delta = [0, 0];\r\n    var parent = null;\r\n    // delta [0,0] will do fine with position: fixed elements,\r\n    // position:absolute needs offsetParent deltas\r\n    if (Element.getStyle(element, 'position') == 'absolute') {\r\n      parent = element.getOffsetParent();\r\n      delta = parent.viewportOffset();\r\n    }\r\n\r\n    // correct by body offsets (fixes Safari)\r\n    if (parent == document.body) {\r\n      delta[0] -= document.body.offsetLeft;\r\n      delta[1] -= document.body.offsetTop;\r\n    }\r\n\r\n    // set position\r\n    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\r\n    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\r\n    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';\r\n    if (options.setHeight) element.style.height = source.offsetHeight + 'px';\r\n    return element;\r\n  }\r\n};\r\n\r\nElement.Methods.identify.counter = 1;\r\n\r\nObject.extend(Element.Methods, {\r\n  getElementsBySelector: Element.Methods.select,\r\n  childElements: Element.Methods.immediateDescendants\r\n});\r\n\r\nElement._attributeTranslations = {\r\n  write: {\r\n    names: {\r\n      className: 'class',\r\n      htmlFor:   'for'\r\n    },\r\n    values: { }\r\n  }\r\n};\r\n\r\nif (Prototype.Browser.Opera) {\r\n  Element.Methods.getStyle = Element.Methods.getStyle.wrap(\r\n    function(proceed, element, style) {\r\n      switch (style) {\r\n        case 'left': case 'top': case 'right': case 'bottom':\r\n          if (proceed(element, 'position') === 'static') return null;\r\n        case 'height': case 'width':\r\n          // returns '0px' for hidden elements; we want it to return null\r\n          if (!Element.visible(element)) return null;\r\n\r\n          // returns the border-box dimensions rather than the content-box\r\n          // dimensions, so we subtract padding and borders from the value\r\n          var dim = parseInt(proceed(element, style), 10);\r\n\r\n          if (dim !== element['offset' + style.capitalize()])\r\n            return dim + 'px';\r\n\r\n          var properties;\r\n          if (style === 'height') {\r\n            properties = ['border-top-width', 'padding-top',\r\n             'padding-bottom', 'border-bottom-width'];\r\n          }\r\n          else {\r\n            properties = ['border-left-width', 'padding-left',\r\n             'padding-right', 'border-right-width'];\r\n          }\r\n          return properties.inject(dim, function(memo, property) {\r\n            var val = proceed(element, property);\r\n            return val === null ? memo : memo - parseInt(val, 10);\r\n          }) + 'px';\r\n        default: return proceed(element, style);\r\n      }\r\n    }\r\n  );\r\n\r\n  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(\r\n    function(proceed, element, attribute) {\r\n      if (attribute === 'title') return element.title;\r\n      return proceed(element, attribute);\r\n    }\r\n  );\r\n}\r\n\r\nelse if (Prototype.Browser.IE) {\r\n  // IE doesn't report offsets correctly for static elements, so we change them\r\n  // to \"relative\" to get the values, then change them back.\r\n  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(\r\n    function(proceed, element) {\r\n      element = $(element);\r\n      var position = element.getStyle('position');\r\n      if (position !== 'static') return proceed(element);\r\n      element.setStyle({ position: 'relative' });\r\n      var value = proceed(element);\r\n      element.setStyle({ position: position });\r\n      return value;\r\n    }\r\n  );\r\n\r\n  $w('positionedOffset viewportOffset').each(function(method) {\r\n    Element.Methods[method] = Element.Methods[method].wrap(\r\n      function(proceed, element) {\r\n        element = $(element);\r\n        var position = element.getStyle('position');\r\n        if (position !== 'static') return proceed(element);\r\n        // Trigger hasLayout on the offset parent so that IE6 reports\r\n        // accurate offsetTop and offsetLeft values for position: fixed.\r\n        var offsetParent = element.getOffsetParent();\r\n        if (offsetParent && offsetParent.getStyle('position') === 'fixed')\r\n          offsetParent.setStyle({ zoom: 1 });\r\n        element.setStyle({ position: 'relative' });\r\n        var value = proceed(element);\r\n        element.setStyle({ position: position });\r\n        return value;\r\n      }\r\n    );\r\n  });\r\n\r\n  Element.Methods.getStyle = function(element, style) {\r\n    element = $(element);\r\n    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();\r\n    var value = element.style[style];\r\n    if (!value && element.currentStyle) value = element.currentStyle[style];\r\n\r\n    if (style == 'opacity') {\r\n      if (value = (element.getStyle('filter') || '').match(/alpha\\(opacity=(.*)\\)/))\r\n        if (value[1]) return parseFloat(value[1]) / 100;\r\n      return 1.0;\r\n    }\r\n\r\n    if (value == 'auto') {\r\n      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))\r\n        return element['offset' + style.capitalize()] + 'px';\r\n      return null;\r\n    }\r\n    return value;\r\n  };\r\n\r\n  Element.Methods.setOpacity = function(element, value) {\r\n    function stripAlpha(filter){\r\n      return filter.replace(/alpha\\([^\\)]*\\)/gi,'');\r\n    }\r\n    element = $(element);\r\n    var currentStyle = element.currentStyle;\r\n    if ((currentStyle && !currentStyle.hasLayout) ||\r\n      (!currentStyle && element.style.zoom == 'normal'))\r\n        element.style.zoom = 1;\r\n\r\n    var filter = element.getStyle('filter'), style = element.style;\r\n    if (value == 1 || value === '') {\r\n      (filter = stripAlpha(filter)) ?\r\n        style.filter = filter : style.removeAttribute('filter');\r\n      return element;\r\n    } else if (value < 0.00001) value = 0;\r\n    style.filter = stripAlpha(filter) +\r\n      'alpha(opacity=' + (value * 100) + ')';\r\n    return element;\r\n  };\r\n\r\n  Element._attributeTranslations = {\r\n    read: {\r\n      names: {\r\n        'class': 'className',\r\n        'for':   'htmlFor'\r\n      },\r\n      values: {\r\n        _getAttr: function(element, attribute) {\r\n          return element.getAttribute(attribute, 2);\r\n        },\r\n        _getAttrNode: function(element, attribute) {\r\n          var node = element.getAttributeNode(attribute);\r\n          return node ? node.value : \"\";\r\n        },\r\n        _getEv: function(element, attribute) {\r\n          attribute = element.getAttribute(attribute);\r\n          return attribute ? attribute.toString().slice(23, -2) : null;\r\n        },\r\n        _flag: function(element, attribute) {\r\n          return $(element).hasAttribute(attribute) ? attribute : null;\r\n        },\r\n        style: function(element) {\r\n          return element.style.cssText.toLowerCase();\r\n        },\r\n        title: function(element) {\r\n          return element.title;\r\n        }\r\n      }\r\n    }\r\n  };\r\n\r\n  Element._attributeTranslations.write = {\r\n    names: Object.extend({\r\n      cellpadding: 'cellPadding',\r\n      cellspacing: 'cellSpacing'\r\n    }, Element._attributeTranslations.read.names),\r\n    values: {\r\n      checked: function(element, value) {\r\n        element.checked = !!value;\r\n      },\r\n\r\n      style: function(element, value) {\r\n        element.style.cssText = value ? value : '';\r\n      }\r\n    }\r\n  };\r\n\r\n  Element._attributeTranslations.has = {};\r\n\r\n  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +\r\n      'encType maxLength readOnly longDesc').each(function(attr) {\r\n    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;\r\n    Element._attributeTranslations.has[attr.toLowerCase()] = attr;\r\n  });\r\n\r\n  (function(v) {\r\n    Object.extend(v, {\r\n      href:        v._getAttr,\r\n      src:         v._getAttr,\r\n      type:        v._getAttr,\r\n      action:      v._getAttrNode,\r\n      disabled:    v._flag,\r\n      checked:     v._flag,\r\n      readonly:    v._flag,\r\n      multiple:    v._flag,\r\n      onload:      v._getEv,\r\n      onunload:    v._getEv,\r\n      onclick:     v._getEv,\r\n      ondblclick:  v._getEv,\r\n      onmousedown: v._getEv,\r\n      onmouseup:   v._getEv,\r\n      onmouseover: v._getEv,\r\n      onmousemove: v._getEv,\r\n      onmouseout:  v._getEv,\r\n      onfocus:     v._getEv,\r\n      onblur:      v._getEv,\r\n      onkeypress:  v._getEv,\r\n      onkeydown:   v._getEv,\r\n      onkeyup:     v._getEv,\r\n      onsubmit:    v._getEv,\r\n      onreset:     v._getEv,\r\n      onselect:    v._getEv,\r\n      onchange:    v._getEv\r\n    });\r\n  })(Element._attributeTranslations.read.values);\r\n}\r\n\r\nelse if (Prototype.Browser.Gecko && /rv:1\\.8\\.0/.test(navigator.userAgent)) {\r\n  Element.Methods.setOpacity = function(element, value) {\r\n    element = $(element);\r\n    element.style.opacity = (value == 1) ? 0.999999 :\r\n      (value === '') ? '' : (value < 0.00001) ? 0 : value;\r\n    return element;\r\n  };\r\n}\r\n\r\nelse if (Prototype.Browser.WebKit) {\r\n  Element.Methods.setOpacity = function(element, value) {\r\n    element = $(element);\r\n    element.style.opacity = (value == 1 || value === '') ? '' :\r\n      (value < 0.00001) ? 0 : value;\r\n\r\n    if (value == 1)\r\n      if(element.tagName == 'IMG' && element.width) {\r\n        element.width++; element.width--;\r\n      } else try {\r\n        var n = document.createTextNode(' ');\r\n        element.appendChild(n);\r\n        element.removeChild(n);\r\n      } catch (e) { }\r\n\r\n    return element;\r\n  };\r\n\r\n  // Safari returns margins on body which is incorrect if the child is absolutely\r\n  // positioned.  For performance reasons, redefine Element#cumulativeOffset for\r\n  // KHTML/WebKit only.\r\n  Element.Methods.cumulativeOffset = function(element) {\r\n    var valueT = 0, valueL = 0;\r\n    do {\r\n      valueT += element.offsetTop  || 0;\r\n      valueL += element.offsetLeft || 0;\r\n      if (element.offsetParent == document.body)\r\n        if (Element.getStyle(element, 'position') == 'absolute') break;\r\n\r\n      element = element.offsetParent;\r\n    } while (element);\r\n\r\n    return Element._returnOffset(valueL, valueT);\r\n  };\r\n}\r\n\r\nif (Prototype.Browser.IE || Prototype.Browser.Opera) {\r\n  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements\r\n  Element.Methods.update = function(element, content) {\r\n    element = $(element);\r\n\r\n    if (content && content.toElement) content = content.toElement();\r\n    if (Object.isElement(content)) return element.update().insert(content);\r\n\r\n    content = Object.toHTML(content);\r\n    var tagName = element.tagName.toUpperCase();\r\n\r\n    if (tagName in Element._insertionTranslations.tags) {\r\n      $A(element.childNodes).each(function(node) { element.removeChild(node) });\r\n      Element._getContentFromAnonymousElement(tagName, content.stripScripts())\r\n        .each(function(node) { element.appendChild(node) });\r\n    }\r\n    else element.innerHTML = content.stripScripts();\r\n\r\n    content.evalScripts.bind(content).defer();\r\n    return element;\r\n  };\r\n}\r\n\r\nif ('outerHTML' in document.createElement('div')) {\r\n  Element.Methods.replace = function(element, content) {\r\n    element = $(element);\r\n\r\n    if (content && content.toElement) content = content.toElement();\r\n    if (Object.isElement(content)) {\r\n      element.parentNode.replaceChild(content, element);\r\n      return element;\r\n    }\r\n\r\n    content = Object.toHTML(content);\r\n    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();\r\n\r\n    if (Element._insertionTranslations.tags[tagName]) {\r\n      var nextSibling = element.next();\r\n      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\r\n      parent.removeChild(element);\r\n      if (nextSibling)\r\n        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });\r\n      else\r\n        fragments.each(function(node) { parent.appendChild(node) });\r\n    }\r\n    else element.outerHTML = content.stripScripts();\r\n\r\n    content.evalScripts.bind(content).defer();\r\n    return element;\r\n  };\r\n}\r\n\r\nElement._returnOffset = function(l, t) {\r\n  var result = [l, t];\r\n  result.left = l;\r\n  result.top = t;\r\n  return result;\r\n};\r\n\r\nElement._getContentFromAnonymousElement = function(tagName, html) {\r\n  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];\r\n  if (t) {\r\n    div.innerHTML = t[0] + html + t[1];\r\n    t[2].times(function() { div = div.firstChild });\r\n  } else div.innerHTML = html;\r\n  return $A(div.childNodes);\r\n};\r\n\r\nElement._insertionTranslations = {\r\n  before: function(element, node) {\r\n    element.parentNode.insertBefore(node, element);\r\n  },\r\n  top: function(element, node) {\r\n    element.insertBefore(node, element.firstChild);\r\n  },\r\n  bottom: function(element, node) {\r\n    element.appendChild(node);\r\n  },\r\n  after: function(element, node) {\r\n    element.parentNode.insertBefore(node, element.nextSibling);\r\n  },\r\n  tags: {\r\n    TABLE:  ['<table>',                '</table>',                   1],\r\n    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],\r\n    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],\r\n    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],\r\n    SELECT: ['<select>',               '</select>',                  1]\r\n  }\r\n};\r\n\r\n(function() {\r\n  Object.extend(this.tags, {\r\n    THEAD: this.tags.TBODY,\r\n    TFOOT: this.tags.TBODY,\r\n    TH:    this.tags.TD\r\n  });\r\n}).call(Element._insertionTranslations);\r\n\r\nElement.Methods.Simulated = {\r\n  hasAttribute: function(element, attribute) {\r\n    attribute = Element._attributeTranslations.has[attribute] || attribute;\r\n    var node = $(element).getAttributeNode(attribute);\r\n    return node && node.specified;\r\n  }\r\n};\r\n\r\nElement.Methods.ByTag = { };\r\n\r\nObject.extend(Element, Element.Methods);\r\n\r\nif (!Prototype.BrowserFeatures.ElementExtensions &&\r\n    document.createElement('div').__proto__) {\r\n  window.HTMLElement = { };\r\n  window.HTMLElement.prototype = document.createElement('div').__proto__;\r\n  Prototype.BrowserFeatures.ElementExtensions = true;\r\n}\r\n\r\nElement.extend = (function() {\r\n  if (Prototype.BrowserFeatures.SpecificElementExtensions)\r\n    return Prototype.K;\r\n\r\n  var Methods = { }, ByTag = Element.Methods.ByTag;\r\n\r\n  var extend = Object.extend(function(element) {\r\n    if (!element || element._extendedByPrototype ||\r\n        element.nodeType != 1 || element == window) return element;\r\n\r\n    var methods = Object.clone(Methods),\r\n      tagName = element.tagName, property, value;\r\n\r\n    // extend methods for specific tags\r\n    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);\r\n\r\n    for (property in methods) {\r\n      value = methods[property];\r\n      if (Object.isFunction(value) && !(property in element))\r\n        element[property] = value.methodize();\r\n    }\r\n\r\n    element._extendedByPrototype = Prototype.emptyFunction;\r\n    return element;\r\n\r\n  }, {\r\n    refresh: function() {\r\n      // extend methods for all tags (Safari doesn't need this)\r\n      if (!Prototype.BrowserFeatures.ElementExtensions) {\r\n        Object.extend(Methods, Element.Methods);\r\n        Object.extend(Methods, Element.Methods.Simulated);\r\n      }\r\n    }\r\n  });\r\n\r\n  extend.refresh();\r\n  return extend;\r\n})();\r\n\r\nElement.hasAttribute = function(element, attribute) {\r\n  if (element.hasAttribute) return element.hasAttribute(attribute);\r\n  return Element.Methods.Simulated.hasAttribute(element, attribute);\r\n};\r\n\r\nElement.addMethods = function(methods) {\r\n  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;\r\n\r\n  if (!methods) {\r\n    Object.extend(Form, Form.Methods);\r\n    Object.extend(Form.Element, Form.Element.Methods);\r\n    Object.extend(Element.Methods.ByTag, {\r\n      \"FORM\":     Object.clone(Form.Methods),\r\n      \"INPUT\":    Object.clone(Form.Element.Methods),\r\n      \"SELECT\":   Object.clone(Form.Element.Methods),\r\n      \"TEXTAREA\": Object.clone(Form.Element.Methods)\r\n    });\r\n  }\r\n\r\n  if (arguments.length == 2) {\r\n    var tagName = methods;\r\n    methods = arguments[1];\r\n  }\r\n\r\n  if (!tagName) Object.extend(Element.Methods, methods || { });\r\n  else {\r\n    if (Object.isArray(tagName)) tagName.each(extend);\r\n    else extend(tagName);\r\n  }\r\n\r\n  function extend(tagName) {\r\n    tagName = tagName.toUpperCase();\r\n    if (!Element.Methods.ByTag[tagName])\r\n      Element.Methods.ByTag[tagName] = { };\r\n    Object.extend(Element.Methods.ByTag[tagName], methods);\r\n  }\r\n\r\n  function copy(methods, destination, onlyIfAbsent) {\r\n    onlyIfAbsent = onlyIfAbsent || false;\r\n    for (var property in methods) {\r\n      var value = methods[property];\r\n      if (!Object.isFunction(value)) continue;\r\n      if (!onlyIfAbsent || !(property in destination))\r\n        destination[property] = value.methodize();\r\n    }\r\n  }\r\n\r\n  function findDOMClass(tagName) {\r\n    var klass;\r\n    var trans = {\r\n      \"OPTGROUP\": \"OptGroup\", \"TEXTAREA\": \"TextArea\", \"P\": \"Paragraph\",\r\n      \"FIELDSET\": \"FieldSet\", \"UL\": \"UList\", \"OL\": \"OList\", \"DL\": \"DList\",\r\n      \"DIR\": \"Directory\", \"H1\": \"Heading\", \"H2\": \"Heading\", \"H3\": \"Heading\",\r\n      \"H4\": \"Heading\", \"H5\": \"Heading\", \"H6\": \"Heading\", \"Q\": \"Quote\",\r\n      \"INS\": \"Mod\", \"DEL\": \"Mod\", \"A\": \"Anchor\", \"IMG\": \"Image\", \"CAPTION\":\r\n      \"TableCaption\", \"COL\": \"TableCol\", \"COLGROUP\": \"TableCol\", \"THEAD\":\r\n      \"TableSection\", \"TFOOT\": \"TableSection\", \"TBODY\": \"TableSection\", \"TR\":\r\n      \"TableRow\", \"TH\": \"TableCell\", \"TD\": \"TableCell\", \"FRAMESET\":\r\n      \"FrameSet\", \"IFRAME\": \"IFrame\"\r\n    };\r\n    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';\r\n    if (window[klass]) return window[klass];\r\n    klass = 'HTML' + tagName + 'Element';\r\n    if (window[klass]) return window[klass];\r\n    klass = 'HTML' + tagName.capitalize() + 'Element';\r\n    if (window[klass]) return window[klass];\r\n\r\n    window[klass] = { };\r\n    window[klass].prototype = document.createElement(tagName).__proto__;\r\n    return window[klass];\r\n  }\r\n\r\n  if (F.ElementExtensions) {\r\n    copy(Element.Methods, HTMLElement.prototype);\r\n    copy(Element.Methods.Simulated, HTMLElement.prototype, true);\r\n  }\r\n\r\n  if (F.SpecificElementExtensions) {\r\n    for (var tag in Element.Methods.ByTag) {\r\n      var klass = findDOMClass(tag);\r\n      if (Object.isUndefined(klass)) continue;\r\n      copy(T[tag], klass.prototype);\r\n    }\r\n  }\r\n\r\n  Object.extend(Element, Element.Methods);\r\n  delete Element.ByTag;\r\n\r\n  if (Element.extend.refresh) Element.extend.refresh();\r\n  Element.cache = { };\r\n};\r\n\r\ndocument.viewport = {\r\n  getDimensions: function() {\r\n    var dimensions = { };\r\n    var B = Prototype.Browser;\r\n    $w('width height').each(function(d) {\r\n      var D = d.capitalize();\r\n      dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :\r\n        (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];\r\n    });\r\n    return dimensions;\r\n  },\r\n\r\n  getWidth: function() {\r\n    return this.getDimensions().width;\r\n  },\r\n\r\n  getHeight: function() {\r\n    return this.getDimensions().height;\r\n  },\r\n\r\n  getScrollOffsets: function() {\r\n    return Element._returnOffset(\r\n      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,\r\n      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);\r\n  }\r\n};\r\n/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,\r\n * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style\r\n * license.  Please see http://www.yui-ext.com/ for more information. */\r\n\r\nvar Selector = Class.create({\r\n  initialize: function(expression) {\r\n    this.expression = expression.strip();\r\n    this.compileMatcher();\r\n  },\r\n\r\n  shouldUseXPath: function() {\r\n    if (!Prototype.BrowserFeatures.XPath) return false;\r\n\r\n    var e = this.expression;\r\n\r\n    // Safari 3 chokes on :*-of-type and :empty\r\n    if (Prototype.Browser.WebKit &&\r\n     (e.include(\"-of-type\") || e.include(\":empty\")))\r\n      return false;\r\n\r\n    // XPath can't do namespaced attributes, nor can it read\r\n    // the \"checked\" property from DOM nodes\r\n    if ((/(\\[[\\w-]*?:|:checked)/).test(this.expression))\r\n      return false;\r\n\r\n    return true;\r\n  },\r\n\r\n  compileMatcher: function() {\r\n    if (this.shouldUseXPath())\r\n      return this.compileXPathMatcher();\r\n\r\n    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,\r\n        c = Selector.criteria, le, p, m;\r\n\r\n    if (Selector._cache[e]) {\r\n      this.matcher = Selector._cache[e];\r\n      return;\r\n    }\r\n\r\n    this.matcher = [\"this.matcher = function(root) {\",\r\n                    \"var r = root, h = Selector.handlers, c = false, n;\"];\r\n\r\n    while (e && le != e && (/\\S/).test(e)) {\r\n      le = e;\r\n      for (var i in ps) {\r\n        p = ps[i];\r\n        if (m = e.match(p)) {\r\n          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :\r\n    \t      new Template(c[i]).evaluate(m));\r\n          e = e.replace(m[0], '');\r\n          break;\r\n        }\r\n      }\r\n    }\r\n\r\n    this.matcher.push(\"return h.unique(n);\\n}\");\r\n    eval(this.matcher.join('\\n'));\r\n    Selector._cache[this.expression] = this.matcher;\r\n  },\r\n\r\n  compileXPathMatcher: function() {\r\n    var e = this.expression, ps = Selector.patterns,\r\n        x = Selector.xpath, le, m;\r\n\r\n    if (Selector._cache[e]) {\r\n      this.xpath = Selector._cache[e]; return;\r\n    }\r\n\r\n    this.matcher = ['.//*'];\r\n    while (e && le != e && (/\\S/).test(e)) {\r\n      le = e;\r\n      for (var i in ps) {\r\n        if (m = e.match(ps[i])) {\r\n          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :\r\n            new Template(x[i]).evaluate(m));\r\n          e = e.replace(m[0], '');\r\n          break;\r\n        }\r\n      }\r\n    }\r\n\r\n    this.xpath = this.matcher.join('');\r\n    Selector._cache[this.expression] = this.xpath;\r\n  },\r\n\r\n  findElements: function(root) {\r\n    root = root || document;\r\n    if (this.xpath) return document._getElementsByXPath(this.xpath, root);\r\n    return this.matcher(root);\r\n  },\r\n\r\n  match: function(element) {\r\n    this.tokens = [];\r\n\r\n    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;\r\n    var le, p, m;\r\n\r\n    while (e && le !== e && (/\\S/).test(e)) {\r\n      le = e;\r\n      for (var i in ps) {\r\n        p = ps[i];\r\n        if (m = e.match(p)) {\r\n          // use the Selector.assertions methods unless the selector\r\n          // is too complex.\r\n          if (as[i]) {\r\n            this.tokens.push([i, Object.clone(m)]);\r\n            e = e.replace(m[0], '');\r\n          } else {\r\n            // reluctantly do a document-wide search\r\n            // and look for a match in the array\r\n            return this.findElements(document).include(element);\r\n          }\r\n        }\r\n      }\r\n    }\r\n\r\n    var match = true, name, matches;\r\n    for (var i = 0, token; token = this.tokens[i]; i++) {\r\n      name = token[0], matches = token[1];\r\n      if (!Selector.assertions[name](element, matches)) {\r\n        match = false; break;\r\n      }\r\n    }\r\n\r\n    return match;\r\n  },\r\n\r\n  toString: function() {\r\n    return this.expression;\r\n  },\r\n\r\n  inspect: function() {\r\n    return \"#<Selector:\" + this.expression.inspect() + \">\";\r\n  }\r\n});\r\n\r\nObject.extend(Selector, {\r\n  _cache: { },\r\n\r\n  xpath: {\r\n    descendant:   \"//*\",\r\n    child:        \"/*\",\r\n    adjacent:     \"/following-sibling::*[1]\",\r\n    laterSibling: '/following-sibling::*',\r\n    tagName:      function(m) {\r\n      if (m[1] == '*') return '';\r\n      return \"[local-name()='\" + m[1].toLowerCase() +\r\n             \"' or local-name()='\" + m[1].toUpperCase() + \"']\";\r\n    },\r\n    className:    \"[contains(concat(' ', @class, ' '), ' #{1} ')]\",\r\n    id:           \"[@id='#{1}']\",\r\n    attrPresence: function(m) {\r\n      m[1] = m[1].toLowerCase();\r\n      return new Template(\"[@#{1}]\").evaluate(m);\r\n    },\r\n    attr: function(m) {\r\n      m[1] = m[1].toLowerCase();\r\n      m[3] = m[5] || m[6];\r\n      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);\r\n    },\r\n    pseudo: function(m) {\r\n      var h = Selector.xpath.pseudos[m[1]];\r\n      if (!h) return '';\r\n      if (Object.isFunction(h)) return h(m);\r\n      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);\r\n    },\r\n    operators: {\r\n      '=':  \"[@#{1}='#{3}']\",\r\n      '!=': \"[@#{1}!='#{3}']\",\r\n      '^=': \"[starts-with(@#{1}, '#{3}')]\",\r\n      '$=': \"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']\",\r\n      '*=': \"[contains(@#{1}, '#{3}')]\",\r\n      '~=': \"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]\",\r\n      '|=': \"[contains(concat('-', @#{1}, '-'), '-#{3}-')]\"\r\n    },\r\n    pseudos: {\r\n      'first-child': '[not(preceding-sibling::*)]',\r\n      'last-child':  '[not(following-sibling::*)]',\r\n      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',\r\n      'empty':       \"[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \\t\\r\\n', '') = '')]\",\r\n      'checked':     \"[@checked]\",\r\n      'disabled':    \"[@disabled]\",\r\n      'enabled':     \"[not(@disabled)]\",\r\n      'not': function(m) {\r\n        var e = m[6], p = Selector.patterns,\r\n            x = Selector.xpath, le, v;\r\n\r\n        var exclusion = [];\r\n        while (e && le != e && (/\\S/).test(e)) {\r\n          le = e;\r\n          for (var i in p) {\r\n            if (m = e.match(p[i])) {\r\n              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);\r\n              exclusion.push(\"(\" + v.substring(1, v.length - 1) + \")\");\r\n              e = e.replace(m[0], '');\r\n              break;\r\n            }\r\n          }\r\n        }\r\n        return \"[not(\" + exclusion.join(\" and \") + \")]\";\r\n      },\r\n      'nth-child':      function(m) {\r\n        return Selector.xpath.pseudos.nth(\"(count(./preceding-sibling::*) + 1) \", m);\r\n      },\r\n      'nth-last-child': function(m) {\r\n        return Selector.xpath.pseudos.nth(\"(count(./following-sibling::*) + 1) \", m);\r\n      },\r\n      'nth-of-type':    function(m) {\r\n        return Selector.xpath.pseudos.nth(\"position() \", m);\r\n      },\r\n      'nth-last-of-type': function(m) {\r\n        return Selector.xpath.pseudos.nth(\"(last() + 1 - position()) \", m);\r\n      },\r\n      'first-of-type':  function(m) {\r\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-of-type'](m);\r\n      },\r\n      'last-of-type':   function(m) {\r\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-last-of-type'](m);\r\n      },\r\n      'only-of-type':   function(m) {\r\n        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);\r\n      },\r\n      nth: function(fragment, m) {\r\n        var mm, formula = m[6], predicate;\r\n        if (formula == 'even') formula = '2n+0';\r\n        if (formula == 'odd')  formula = '2n+1';\r\n        if (mm = formula.match(/^(\\d+)$/)) // digit only\r\n          return '[' + fragment + \"= \" + mm[1] + ']';\r\n        if (mm = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\r\n          if (mm[1] == \"-\") mm[1] = -1;\r\n          var a = mm[1] ? Number(mm[1]) : 1;\r\n          var b = mm[2] ? Number(mm[2]) : 0;\r\n          predicate = \"[((#{fragment} - #{b}) mod #{a} = 0) and \" +\r\n          \"((#{fragment} - #{b}) div #{a} >= 0)]\";\r\n          return new Template(predicate).evaluate({\r\n            fragment: fragment, a: a, b: b });\r\n        }\r\n      }\r\n    }\r\n  },\r\n\r\n  criteria: {\r\n    tagName:      'n = h.tagName(n, r, \"#{1}\", c);      c = false;',\r\n    className:    'n = h.className(n, r, \"#{1}\", c);    c = false;',\r\n    id:           'n = h.id(n, r, \"#{1}\", c);           c = false;',\r\n    attrPresence: 'n = h.attrPresence(n, r, \"#{1}\", c); c = false;',\r\n    attr: function(m) {\r\n      m[3] = (m[5] || m[6]);\r\n      return new Template('n = h.attr(n, r, \"#{1}\", \"#{3}\", \"#{2}\", c); c = false;').evaluate(m);\r\n    },\r\n    pseudo: function(m) {\r\n      if (m[6]) m[6] = m[6].replace(/\"/g, '\\\\\"');\r\n      return new Template('n = h.pseudo(n, \"#{1}\", \"#{6}\", r, c); c = false;').evaluate(m);\r\n    },\r\n    descendant:   'c = \"descendant\";',\r\n    child:        'c = \"child\";',\r\n    adjacent:     'c = \"adjacent\";',\r\n    laterSibling: 'c = \"laterSibling\";'\r\n  },\r\n\r\n  patterns: {\r\n    // combinators must be listed first\r\n    // (and descendant needs to be last combinator)\r\n    laterSibling: /^\\s*~\\s*/,\r\n    child:        /^\\s*>\\s*/,\r\n    adjacent:     /^\\s*\\+\\s*/,\r\n    descendant:   /^\\s/,\r\n\r\n    // selectors follow\r\n    tagName:      /^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,\r\n    id:           /^#([\\w\\-\\*]+)(\\b|$)/,\r\n    className:    /^\\.([\\w\\-\\*]+)(\\b|$)/,\r\n    pseudo:\r\n/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,\r\n    attrPresence: /^\\[([\\w]+)\\]/,\r\n    attr:         /\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*((['\"])([^\\4]*?)\\4|([^'\"][^\\]]*?)))?\\]/\r\n  },\r\n\r\n  // for Selector.match and Element#match\r\n  assertions: {\r\n    tagName: function(element, matches) {\r\n      return matches[1].toUpperCase() == element.tagName.toUpperCase();\r\n    },\r\n\r\n    className: function(element, matches) {\r\n      return Element.hasClassName(element, matches[1]);\r\n    },\r\n\r\n    id: function(element, matches) {\r\n      return element.id === matches[1];\r\n    },\r\n\r\n    attrPresence: function(element, matches) {\r\n      return Element.hasAttribute(element, matches[1]);\r\n    },\r\n\r\n    attr: function(element, matches) {\r\n      var nodeValue = Element.readAttribute(element, matches[1]);\r\n      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);\r\n    }\r\n  },\r\n\r\n  handlers: {\r\n    // UTILITY FUNCTIONS\r\n    // joins two collections\r\n    concat: function(a, b) {\r\n      for (var i = 0, node; node = b[i]; i++)\r\n        a.push(node);\r\n      return a;\r\n    },\r\n\r\n    // marks an array of nodes for counting\r\n    mark: function(nodes) {\r\n      var _true = Prototype.emptyFunction;\r\n      for (var i = 0, node; node = nodes[i]; i++)\r\n        node._countedByPrototype = _true;\r\n      return nodes;\r\n    },\r\n\r\n    unmark: function(nodes) {\r\n      for (var i = 0, node; node = nodes[i]; i++)\r\n        node._countedByPrototype = undefined;\r\n      return nodes;\r\n    },\r\n\r\n    // mark each child node with its position (for nth calls)\r\n    // \"ofType\" flag indicates whether we're indexing for nth-of-type\r\n    // rather than nth-child\r\n    index: function(parentNode, reverse, ofType) {\r\n      parentNode._countedByPrototype = Prototype.emptyFunction;\r\n      if (reverse) {\r\n        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {\r\n          var node = nodes[i];\r\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\r\n        }\r\n      } else {\r\n        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)\r\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\r\n      }\r\n    },\r\n\r\n    // filters out duplicates and extends all nodes\r\n    unique: function(nodes) {\r\n      if (nodes.length == 0) return nodes;\r\n      var results = [], n;\r\n      for (var i = 0, l = nodes.length; i < l; i++)\r\n        if (!(n = nodes[i])._countedByPrototype) {\r\n          n._countedByPrototype = Prototype.emptyFunction;\r\n          results.push(Element.extend(n));\r\n        }\r\n      return Selector.handlers.unmark(results);\r\n    },\r\n\r\n    // COMBINATOR FUNCTIONS\r\n    descendant: function(nodes) {\r\n      var h = Selector.handlers;\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        h.concat(results, node.getElementsByTagName('*'));\r\n      return results;\r\n    },\r\n\r\n    child: function(nodes) {\r\n      var h = Selector.handlers;\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\r\n        for (var j = 0, child; child = node.childNodes[j]; j++)\r\n          if (child.nodeType == 1 && child.tagName != '!') results.push(child);\r\n      }\r\n      return results;\r\n    },\r\n\r\n    adjacent: function(nodes) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\r\n        var next = this.nextElementSibling(node);\r\n        if (next) results.push(next);\r\n      }\r\n      return results;\r\n    },\r\n\r\n    laterSibling: function(nodes) {\r\n      var h = Selector.handlers;\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        h.concat(results, Element.nextSiblings(node));\r\n      return results;\r\n    },\r\n\r\n    nextElementSibling: function(node) {\r\n      while (node = node.nextSibling)\r\n\t      if (node.nodeType == 1) return node;\r\n      return null;\r\n    },\r\n\r\n    previousElementSibling: function(node) {\r\n      while (node = node.previousSibling)\r\n        if (node.nodeType == 1) return node;\r\n      return null;\r\n    },\r\n\r\n    // TOKEN FUNCTIONS\r\n    tagName: function(nodes, root, tagName, combinator) {\r\n      var uTagName = tagName.toUpperCase();\r\n      var results = [], h = Selector.handlers;\r\n      if (nodes) {\r\n        if (combinator) {\r\n          // fastlane for ordinary descendant combinators\r\n          if (combinator == \"descendant\") {\r\n            for (var i = 0, node; node = nodes[i]; i++)\r\n              h.concat(results, node.getElementsByTagName(tagName));\r\n            return results;\r\n          } else nodes = this[combinator](nodes);\r\n          if (tagName == \"*\") return nodes;\r\n        }\r\n        for (var i = 0, node; node = nodes[i]; i++)\r\n          if (node.tagName.toUpperCase() === uTagName) results.push(node);\r\n        return results;\r\n      } else return root.getElementsByTagName(tagName);\r\n    },\r\n\r\n    id: function(nodes, root, id, combinator) {\r\n      var targetNode = $(id), h = Selector.handlers;\r\n      if (!targetNode) return [];\r\n      if (!nodes && root == document) return [targetNode];\r\n      if (nodes) {\r\n        if (combinator) {\r\n          if (combinator == 'child') {\r\n            for (var i = 0, node; node = nodes[i]; i++)\r\n              if (targetNode.parentNode == node) return [targetNode];\r\n          } else if (combinator == 'descendant') {\r\n            for (var i = 0, node; node = nodes[i]; i++)\r\n              if (Element.descendantOf(targetNode, node)) return [targetNode];\r\n          } else if (combinator == 'adjacent') {\r\n            for (var i = 0, node; node = nodes[i]; i++)\r\n              if (Selector.handlers.previousElementSibling(targetNode) == node)\r\n                return [targetNode];\r\n          } else nodes = h[combinator](nodes);\r\n        }\r\n        for (var i = 0, node; node = nodes[i]; i++)\r\n          if (node == targetNode) return [targetNode];\r\n        return [];\r\n      }\r\n      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];\r\n    },\r\n\r\n    className: function(nodes, root, className, combinator) {\r\n      if (nodes && combinator) nodes = this[combinator](nodes);\r\n      return Selector.handlers.byClassName(nodes, root, className);\r\n    },\r\n\r\n    byClassName: function(nodes, root, className) {\r\n      if (!nodes) nodes = Selector.handlers.descendant([root]);\r\n      var needle = ' ' + className + ' ';\r\n      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {\r\n        nodeClassName = node.className;\r\n        if (nodeClassName.length == 0) continue;\r\n        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))\r\n          results.push(node);\r\n      }\r\n      return results;\r\n    },\r\n\r\n    attrPresence: function(nodes, root, attr, combinator) {\r\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\r\n      if (nodes && combinator) nodes = this[combinator](nodes);\r\n      var results = [];\r\n      for (var i = 0, node; node = nodes[i]; i++)\r\n        if (Element.hasAttribute(node, attr)) results.push(node);\r\n      return results;\r\n    },\r\n\r\n    attr: function(nodes, root, attr, value, operator, combinator) {\r\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\r\n      if (nodes && combinator) nodes = this[combinator](nodes);\r\n      var handler = Selector.operators[operator], results = [];\r\n      for (var i = 0, node; node = nodes[i]; i++) {\r\n        var nodeValue = Element.readAttribute(node, attr);\r\n        if (nodeValue === null) continue;\r\n        if (handler(nodeValue, value)) results.push(node);\r\n      }\r\n      return results;\r\n    },\r\n\r\n    pseudo: function(nodes, name, value, root, combinator) {\r\n      if (nodes && combinator) nodes = this[combinator](nodes);\r\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\r\n      return Selector.pseudos[name](nodes, value, root);\r\n    }\r\n  },\r\n\r\n  pseudos: {\r\n    'first-child': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\r\n        if (Selector.handlers.previousElementSibling(node)) continue;\r\n          results.push(node);\r\n      }\r\n      return results;\r\n    },\r\n    'last-child': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\r\n        if (Selector.handlers.nextElementSibling(node)) continue;\r\n          results.push(node);\r\n      }\r\n      return results;\r\n    },\r\n    'only-child': function(nodes, value, root) {\r\n      var h = Selector.handlers;\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))\r\n          results.push(node);\r\n      return results;\r\n    },\r\n    'nth-child':        function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, formula, root);\r\n    },\r\n    'nth-last-child':   function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, formula, root, true);\r\n    },\r\n    'nth-of-type':      function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, formula, root, false, true);\r\n    },\r\n    'nth-last-of-type': function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, formula, root, true, true);\r\n    },\r\n    'first-of-type':    function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, \"1\", root, false, true);\r\n    },\r\n    'last-of-type':     function(nodes, formula, root) {\r\n      return Selector.pseudos.nth(nodes, \"1\", root, true, true);\r\n    },\r\n    'only-of-type':     function(nodes, formula, root) {\r\n      var p = Selector.pseudos;\r\n      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);\r\n    },\r\n\r\n    // handles the an+b logic\r\n    getIndices: function(a, b, total) {\r\n      if (a == 0) return b > 0 ? [b] : [];\r\n      return $R(1, total).inject([], function(memo, i) {\r\n        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);\r\n        return memo;\r\n      });\r\n    },\r\n\r\n    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type\r\n    nth: function(nodes, formula, root, reverse, ofType) {\r\n      if (nodes.length == 0) return [];\r\n      if (formula == 'even') formula = '2n+0';\r\n      if (formula == 'odd')  formula = '2n+1';\r\n      var h = Selector.handlers, results = [], indexed = [], m;\r\n      h.mark(nodes);\r\n      for (var i = 0, node; node = nodes[i]; i++) {\r\n        if (!node.parentNode._countedByPrototype) {\r\n          h.index(node.parentNode, reverse, ofType);\r\n          indexed.push(node.parentNode);\r\n        }\r\n      }\r\n      if (formula.match(/^\\d+$/)) { // just a number\r\n        formula = Number(formula);\r\n        for (var i = 0, node; node = nodes[i]; i++)\r\n          if (node.nodeIndex == formula) results.push(node);\r\n      } else if (m = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\r\n        if (m[1] == \"-\") m[1] = -1;\r\n        var a = m[1] ? Number(m[1]) : 1;\r\n        var b = m[2] ? Number(m[2]) : 0;\r\n        var indices = Selector.pseudos.getIndices(a, b, nodes.length);\r\n        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {\r\n          for (var j = 0; j < l; j++)\r\n            if (node.nodeIndex == indices[j]) results.push(node);\r\n        }\r\n      }\r\n      h.unmark(nodes);\r\n      h.unmark(indexed);\r\n      return results;\r\n    },\r\n\r\n    'empty': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\r\n        // IE treats comments as element nodes\r\n        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\\s*$/))) continue;\r\n        results.push(node);\r\n      }\r\n      return results;\r\n    },\r\n\r\n    'not': function(nodes, selector, root) {\r\n      var h = Selector.handlers, selectorType, m;\r\n      var exclusions = new Selector(selector).findElements(root);\r\n      h.mark(exclusions);\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        if (!node._countedByPrototype) results.push(node);\r\n      h.unmark(exclusions);\r\n      return results;\r\n    },\r\n\r\n    'enabled': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        if (!node.disabled) results.push(node);\r\n      return results;\r\n    },\r\n\r\n    'disabled': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        if (node.disabled) results.push(node);\r\n      return results;\r\n    },\r\n\r\n    'checked': function(nodes, value, root) {\r\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\r\n        if (node.checked) results.push(node);\r\n      return results;\r\n    }\r\n  },\r\n\r\n  operators: {\r\n    '=':  function(nv, v) { return nv == v; },\r\n    '!=': function(nv, v) { return nv != v; },\r\n    '^=': function(nv, v) { return nv.startsWith(v); },\r\n    '$=': function(nv, v) { return nv.endsWith(v); },\r\n    '*=': function(nv, v) { return nv.include(v); },\r\n    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },\r\n    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }\r\n  },\r\n\r\n  split: function(expression) {\r\n    var expressions = [];\r\n    expression.scan(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/, function(m) {\r\n      expressions.push(m[1].strip());\r\n    });\r\n    return expressions;\r\n  },\r\n\r\n  matchElements: function(elements, expression) {\r\n    var matches = $$(expression), h = Selector.handlers;\r\n    h.mark(matches);\r\n    for (var i = 0, results = [], element; element = elements[i]; i++)\r\n      if (element._countedByPrototype) results.push(element);\r\n    h.unmark(matches);\r\n    return results;\r\n  },\r\n\r\n  findElement: function(elements, expression, index) {\r\n    if (Object.isNumber(expression)) {\r\n      index = expression; expression = false;\r\n    }\r\n    return Selector.matchElements(elements, expression || '*')[index || 0];\r\n  },\r\n\r\n  findChildElements: function(element, expressions) {\r\n    expressions = Selector.split(expressions.join(','));\r\n    var results = [], h = Selector.handlers;\r\n    for (var i = 0, l = expressions.length, selector; i < l; i++) {\r\n      selector = new Selector(expressions[i].strip());\r\n      h.concat(results, selector.findElements(element));\r\n    }\r\n    return (l > 1) ? h.unique(results) : results;\r\n  }\r\n});\r\n\r\nif (Prototype.Browser.IE) {\r\n  Object.extend(Selector.handlers, {\r\n    // IE returns comment nodes on getElementsByTagName(\"*\").\r\n    // Filter them out.\r\n    concat: function(a, b) {\r\n      for (var i = 0, node; node = b[i]; i++)\r\n        if (node.tagName !== \"!\") a.push(node);\r\n      return a;\r\n    },\r\n\r\n    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.\r\n    unmark: function(nodes) {\r\n      for (var i = 0, node; node = nodes[i]; i++)\r\n        node.removeAttribute('_countedByPrototype');\r\n      return nodes;\r\n    }\r\n  });\r\n}\r\n\r\nfunction $$() {\r\n  return Selector.findChildElements(document, $A(arguments));\r\n}\r\nvar Form = {\r\n  reset: function(form) {\r\n    $(form).reset();\r\n    return form;\r\n  },\r\n\r\n  serializeElements: function(elements, options) {\r\n    if (typeof options != 'object') options = { hash: !!options };\r\n    else if (Object.isUndefined(options.hash)) options.hash = true;\r\n    var key, value, submitted = false, submit = options.submit;\r\n\r\n    var data = elements.inject({ }, function(result, element) {\r\n      if (!element.disabled && element.name) {\r\n        key = element.name; value = $(element).getValue();\r\n        if (value != null && (element.type != 'submit' || (!submitted &&\r\n            submit !== false && (!submit || key == submit) && (submitted = true)))) {\r\n          if (key in result) {\r\n            // a key is already present; construct an array of values\r\n            if (!Object.isArray(result[key])) result[key] = [result[key]];\r\n            result[key].push(value);\r\n          }\r\n          else result[key] = value;\r\n        }\r\n      }\r\n      return result;\r\n    });\r\n\r\n    return options.hash ? data : Object.toQueryString(data);\r\n  }\r\n};\r\n\r\nForm.Methods = {\r\n  serialize: function(form, options) {\r\n    return Form.serializeElements(Form.getElements(form), options);\r\n  },\r\n\r\n  getElements: function(form) {\r\n    return $A($(form).getElementsByTagName('*')).inject([],\r\n      function(elements, child) {\r\n        if (Form.Element.Serializers[child.tagName.toLowerCase()])\r\n          elements.push(Element.extend(child));\r\n        return elements;\r\n      }\r\n    );\r\n  },\r\n\r\n  getInputs: function(form, typeName, name) {\r\n    form = $(form);\r\n    var inputs = form.getElementsByTagName('input');\r\n\r\n    if (!typeName && !name) return $A(inputs).map(Element.extend);\r\n\r\n    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {\r\n      var input = inputs[i];\r\n      if ((typeName && input.type != typeName) || (name && input.name != name))\r\n        continue;\r\n      matchingInputs.push(Element.extend(input));\r\n    }\r\n\r\n    return matchingInputs;\r\n  },\r\n\r\n  disable: function(form) {\r\n    form = $(form);\r\n    Form.getElements(form).invoke('disable');\r\n    return form;\r\n  },\r\n\r\n  enable: function(form) {\r\n    form = $(form);\r\n    Form.getElements(form).invoke('enable');\r\n    return form;\r\n  },\r\n\r\n  findFirstElement: function(form) {\r\n    var elements = $(form).getElements().findAll(function(element) {\r\n      return 'hidden' != element.type && !element.disabled;\r\n    });\r\n    var firstByIndex = elements.findAll(function(element) {\r\n      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;\r\n    }).sortBy(function(element) { return element.tabIndex }).first();\r\n\r\n    return firstByIndex ? firstByIndex : elements.find(function(element) {\r\n      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\r\n    });\r\n  },\r\n\r\n  focusFirstElement: function(form) {\r\n    form = $(form);\r\n    form.findFirstElement().activate();\r\n    return form;\r\n  },\r\n\r\n  request: function(form, options) {\r\n    form = $(form), options = Object.clone(options || { });\r\n\r\n    var params = options.parameters, action = form.readAttribute('action') || '';\r\n    if (action.blank()) action = window.location.href;\r\n    options.parameters = form.serialize(true);\r\n\r\n    if (params) {\r\n      if (Object.isString(params)) params = params.toQueryParams();\r\n      Object.extend(options.parameters, params);\r\n    }\r\n\r\n    if (form.hasAttribute('method') && !options.method)\r\n      options.method = form.method;\r\n\r\n    return new Ajax.Request(action, options);\r\n  }\r\n};\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nForm.Element = {\r\n  focus: function(element) {\r\n    $(element).focus();\r\n    return element;\r\n  },\r\n\r\n  select: function(element) {\r\n    $(element).select();\r\n    return element;\r\n  }\r\n};\r\n\r\nForm.Element.Methods = {\r\n  serialize: function(element) {\r\n    element = $(element);\r\n    if (!element.disabled && element.name) {\r\n      var value = element.getValue();\r\n      if (value != undefined) {\r\n        var pair = { };\r\n        pair[element.name] = value;\r\n        return Object.toQueryString(pair);\r\n      }\r\n    }\r\n    return '';\r\n  },\r\n\r\n  getValue: function(element) {\r\n    element = $(element);\r\n    var method = element.tagName.toLowerCase();\r\n    return Form.Element.Serializers[method](element);\r\n  },\r\n\r\n  setValue: function(element, value) {\r\n    element = $(element);\r\n    var method = element.tagName.toLowerCase();\r\n    Form.Element.Serializers[method](element, value);\r\n    return element;\r\n  },\r\n\r\n  clear: function(element) {\r\n    $(element).value = '';\r\n    return element;\r\n  },\r\n\r\n  present: function(element) {\r\n    return $(element).value != '';\r\n  },\r\n\r\n  activate: function(element) {\r\n    element = $(element);\r\n    try {\r\n      element.focus();\r\n      if (element.select && (element.tagName.toLowerCase() != 'input' ||\r\n          !['button', 'reset', 'submit'].include(element.type)))\r\n        element.select();\r\n    } catch (e) { }\r\n    return element;\r\n  },\r\n\r\n  disable: function(element) {\r\n    element = $(element);\r\n    element.blur();\r\n    element.disabled = true;\r\n    return element;\r\n  },\r\n\r\n  enable: function(element) {\r\n    element = $(element);\r\n    element.disabled = false;\r\n    return element;\r\n  }\r\n};\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nvar Field = Form.Element;\r\nvar $F = Form.Element.Methods.getValue;\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nForm.Element.Serializers = {\r\n  input: function(element, value) {\r\n    switch (element.type.toLowerCase()) {\r\n      case 'checkbox':\r\n      case 'radio':\r\n        return Form.Element.Serializers.inputSelector(element, value);\r\n      default:\r\n        return Form.Element.Serializers.textarea(element, value);\r\n    }\r\n  },\r\n\r\n  inputSelector: function(element, value) {\r\n    if (Object.isUndefined(value)) return element.checked ? element.value : null;\r\n    else element.checked = !!value;\r\n  },\r\n\r\n  textarea: function(element, value) {\r\n    if (Object.isUndefined(value)) return element.value;\r\n    else element.value = value;\r\n  },\r\n\r\n  select: function(element, index) {\r\n    if (Object.isUndefined(index))\r\n      return this[element.type == 'select-one' ?\r\n        'selectOne' : 'selectMany'](element);\r\n    else {\r\n      var opt, value, single = !Object.isArray(index);\r\n      for (var i = 0, length = element.length; i < length; i++) {\r\n        opt = element.options[i];\r\n        value = this.optionValue(opt);\r\n        if (single) {\r\n          if (value == index) {\r\n            opt.selected = true;\r\n            return;\r\n          }\r\n        }\r\n        else opt.selected = index.include(value);\r\n      }\r\n    }\r\n  },\r\n\r\n  selectOne: function(element) {\r\n    var index = element.selectedIndex;\r\n    return index >= 0 ? this.optionValue(element.options[index]) : null;\r\n  },\r\n\r\n  selectMany: function(element) {\r\n    var values, length = element.length;\r\n    if (!length) return null;\r\n\r\n    for (var i = 0, values = []; i < length; i++) {\r\n      var opt = element.options[i];\r\n      if (opt.selected) values.push(this.optionValue(opt));\r\n    }\r\n    return values;\r\n  },\r\n\r\n  optionValue: function(opt) {\r\n    // extend element because hasAttribute may not be native\r\n    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;\r\n  }\r\n};\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nAbstract.TimedObserver = Class.create(PeriodicalExecuter, {\r\n  initialize: function($super, element, frequency, callback) {\r\n    $super(callback, frequency);\r\n    this.element   = $(element);\r\n    this.lastValue = this.getValue();\r\n  },\r\n\r\n  execute: function() {\r\n    var value = this.getValue();\r\n    if (Object.isString(this.lastValue) && Object.isString(value) ?\r\n        this.lastValue != value : String(this.lastValue) != String(value)) {\r\n      this.callback(this.element, value);\r\n      this.lastValue = value;\r\n    }\r\n  }\r\n});\r\n\r\nForm.Element.Observer = Class.create(Abstract.TimedObserver, {\r\n  getValue: function() {\r\n    return Form.Element.getValue(this.element);\r\n  }\r\n});\r\n\r\nForm.Observer = Class.create(Abstract.TimedObserver, {\r\n  getValue: function() {\r\n    return Form.serialize(this.element);\r\n  }\r\n});\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nAbstract.EventObserver = Class.create({\r\n  initialize: function(element, callback) {\r\n    this.element  = $(element);\r\n    this.callback = callback;\r\n\r\n    this.lastValue = this.getValue();\r\n    if (this.element.tagName.toLowerCase() == 'form')\r\n      this.registerFormCallbacks();\r\n    else\r\n      this.registerCallback(this.element);\r\n  },\r\n\r\n  onElementEvent: function() {\r\n    var value = this.getValue();\r\n    if (this.lastValue != value) {\r\n      this.callback(this.element, value);\r\n      this.lastValue = value;\r\n    }\r\n  },\r\n\r\n  registerFormCallbacks: function() {\r\n    Form.getElements(this.element).each(this.registerCallback, this);\r\n  },\r\n\r\n  registerCallback: function(element) {\r\n    if (element.type) {\r\n      switch (element.type.toLowerCase()) {\r\n        case 'checkbox':\r\n        case 'radio':\r\n          Event.observe(element, 'click', this.onElementEvent.bind(this));\r\n          break;\r\n        default:\r\n          Event.observe(element, 'change', this.onElementEvent.bind(this));\r\n          break;\r\n      }\r\n    }\r\n  }\r\n});\r\n\r\nForm.Element.EventObserver = Class.create(Abstract.EventObserver, {\r\n  getValue: function() {\r\n    return Form.Element.getValue(this.element);\r\n  }\r\n});\r\n\r\nForm.EventObserver = Class.create(Abstract.EventObserver, {\r\n  getValue: function() {\r\n    return Form.serialize(this.element);\r\n  }\r\n});\r\nif (!window.Event) var Event = { };\r\n\r\nObject.extend(Event, {\r\n  KEY_BACKSPACE: 8,\r\n  KEY_TAB:       9,\r\n  KEY_RETURN:   13,\r\n  KEY_ESC:      27,\r\n  KEY_LEFT:     37,\r\n  KEY_UP:       38,\r\n  KEY_RIGHT:    39,\r\n  KEY_DOWN:     40,\r\n  KEY_DELETE:   46,\r\n  KEY_HOME:     36,\r\n  KEY_END:      35,\r\n  KEY_PAGEUP:   33,\r\n  KEY_PAGEDOWN: 34,\r\n  KEY_INSERT:   45,\r\n\r\n  cache: { },\r\n\r\n  relatedTarget: function(event) {\r\n    var element;\r\n    switch(event.type) {\r\n      case 'mouseover': element = event.fromElement; break;\r\n      case 'mouseout':  element = event.toElement;   break;\r\n      default: return null;\r\n    }\r\n    return Element.extend(element);\r\n  }\r\n});\r\n\r\nEvent.Methods = (function() {\r\n  var isButton;\r\n\r\n  if (Prototype.Browser.IE) {\r\n    var buttonMap = { 0: 1, 1: 4, 2: 2 };\r\n    isButton = function(event, code) {\r\n      return event.button == buttonMap[code];\r\n    };\r\n\r\n  } else if (Prototype.Browser.WebKit) {\r\n    isButton = function(event, code) {\r\n      switch (code) {\r\n        case 0: return event.which == 1 && !event.metaKey;\r\n        case 1: return event.which == 1 && event.metaKey;\r\n        default: return false;\r\n      }\r\n    };\r\n\r\n  } else {\r\n    isButton = function(event, code) {\r\n      return event.which ? (event.which === code + 1) : (event.button === code);\r\n    };\r\n  }\r\n\r\n  return {\r\n    isLeftClick:   function(event) { return isButton(event, 0) },\r\n    isMiddleClick: function(event) { return isButton(event, 1) },\r\n    isRightClick:  function(event) { return isButton(event, 2) },\r\n\r\n    element: function(event) {\r\n      var node = Event.extend(event).target;\r\n      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);\r\n    },\r\n\r\n    findElement: function(event, expression) {\r\n      var element = Event.element(event);\r\n      if (!expression) return element;\r\n      var elements = [element].concat(element.ancestors());\r\n      return Selector.findElement(elements, expression, 0);\r\n    },\r\n\r\n    pointer: function(event) {\r\n      return {\r\n        x: event.pageX || (event.clientX +\r\n          (document.documentElement.scrollLeft || document.body.scrollLeft)),\r\n        y: event.pageY || (event.clientY +\r\n          (document.documentElement.scrollTop || document.body.scrollTop))\r\n      };\r\n    },\r\n\r\n    pointerX: function(event) { return Event.pointer(event).x },\r\n    pointerY: function(event) { return Event.pointer(event).y },\r\n\r\n    stop: function(event) {\r\n      Event.extend(event);\r\n      event.preventDefault();\r\n      event.stopPropagation();\r\n      event.stopped = true;\r\n    }\r\n  };\r\n})();\r\n\r\nEvent.extend = (function() {\r\n  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {\r\n    m[name] = Event.Methods[name].methodize();\r\n    return m;\r\n  });\r\n\r\n  if (Prototype.Browser.IE) {\r\n    Object.extend(methods, {\r\n      stopPropagation: function() { this.cancelBubble = true },\r\n      preventDefault:  function() { this.returnValue = false },\r\n      inspect: function() { return \"[object Event]\" }\r\n    });\r\n\r\n    return function(event) {\r\n      if (!event) return false;\r\n      if (event._extendedByPrototype) return event;\r\n\r\n      event._extendedByPrototype = Prototype.emptyFunction;\r\n      var pointer = Event.pointer(event);\r\n      Object.extend(event, {\r\n        target: event.srcElement,\r\n        relatedTarget: Event.relatedTarget(event),\r\n        pageX:  pointer.x,\r\n        pageY:  pointer.y\r\n      });\r\n      return Object.extend(event, methods);\r\n    };\r\n\r\n  } else {\r\n    Event.prototype = Event.prototype || document.createEvent(\"HTMLEvents\").__proto__;\r\n    Object.extend(Event.prototype, methods);\r\n    return Prototype.K;\r\n  }\r\n})();\r\n\r\nObject.extend(Event, (function() {\r\n  var cache = Event.cache;\r\n\r\n  function getEventID(element) {\r\n    if (element._prototypeEventID) return element._prototypeEventID[0];\r\n    arguments.callee.id = arguments.callee.id || 1;\r\n    return element._prototypeEventID = [++arguments.callee.id];\r\n  }\r\n\r\n  function getDOMEventName(eventName) {\r\n    if (eventName && eventName.include(':')) return \"dataavailable\";\r\n    return eventName;\r\n  }\r\n\r\n  function getCacheForID(id) {\r\n    return cache[id] = cache[id] || { };\r\n  }\r\n\r\n  function getWrappersForEventName(id, eventName) {\r\n    var c = getCacheForID(id);\r\n    return c[eventName] = c[eventName] || [];\r\n  }\r\n\r\n  function createWrapper(element, eventName, handler) {\r\n    var id = getEventID(element);\r\n    var c = getWrappersForEventName(id, eventName);\r\n    if (c.pluck(\"handler\").include(handler)) return false;\r\n\r\n    var wrapper = function(event) {\r\n      if (!Event || !Event.extend ||\r\n        (event.eventName && event.eventName != eventName))\r\n          return false;\r\n\r\n      Event.extend(event);\r\n      handler.call(element, event);\r\n    };\r\n\r\n    wrapper.handler = handler;\r\n    c.push(wrapper);\r\n    return wrapper;\r\n  }\r\n\r\n  function findWrapper(id, eventName, handler) {\r\n    var c = getWrappersForEventName(id, eventName);\r\n    return c.find(function(wrapper) { return wrapper.handler == handler });\r\n  }\r\n\r\n  function destroyWrapper(id, eventName, handler) {\r\n    var c = getCacheForID(id);\r\n    if (!c[eventName]) return false;\r\n    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));\r\n  }\r\n\r\n  function destroyCache() {\r\n    for (var id in cache)\r\n      for (var eventName in cache[id])\r\n        cache[id][eventName] = null;\r\n  }\r\n\r\n  if (window.attachEvent) {\r\n    window.attachEvent(\"onunload\", destroyCache);\r\n  }\r\n\r\n  return {\r\n    observe: function(element, eventName, handler) {\r\n      element = $(element);\r\n      var name = getDOMEventName(eventName);\r\n\r\n      var wrapper = createWrapper(element, eventName, handler);\r\n      if (!wrapper) return element;\r\n\r\n      if (element.addEventListener) {\r\n        element.addEventListener(name, wrapper, false);\r\n      } else {\r\n        element.attachEvent(\"on\" + name, wrapper);\r\n      }\r\n\r\n      return element;\r\n    },\r\n\r\n    stopObserving: function(element, eventName, handler) {\r\n      element = $(element);\r\n      var id = getEventID(element), name = getDOMEventName(eventName);\r\n\r\n      if (!handler && eventName) {\r\n        getWrappersForEventName(id, eventName).each(function(wrapper) {\r\n          element.stopObserving(eventName, wrapper.handler);\r\n        });\r\n        return element;\r\n\r\n      } else if (!eventName) {\r\n        Object.keys(getCacheForID(id)).each(function(eventName) {\r\n          element.stopObserving(eventName);\r\n        });\r\n        return element;\r\n      }\r\n\r\n      var wrapper = findWrapper(id, eventName, handler);\r\n      if (!wrapper) return element;\r\n\r\n      if (element.removeEventListener) {\r\n        element.removeEventListener(name, wrapper, false);\r\n      } else {\r\n        element.detachEvent(\"on\" + name, wrapper);\r\n      }\r\n\r\n      destroyWrapper(id, eventName, handler);\r\n\r\n      return element;\r\n    },\r\n\r\n    fire: function(element, eventName, memo) {\r\n      element = $(element);\r\n      if (element == document && document.createEvent && !element.dispatchEvent)\r\n        element = document.documentElement;\r\n\r\n      var event;\r\n      if (document.createEvent) {\r\n        event = document.createEvent(\"HTMLEvents\");\r\n        event.initEvent(\"dataavailable\", true, true);\r\n      } else {\r\n        event = document.createEventObject();\r\n        event.eventType = \"ondataavailable\";\r\n      }\r\n\r\n      event.eventName = eventName;\r\n      event.memo = memo || { };\r\n\r\n      if (document.createEvent) {\r\n        element.dispatchEvent(event);\r\n      } else {\r\n        element.fireEvent(event.eventType, event);\r\n      }\r\n\r\n      return Event.extend(event);\r\n    }\r\n  };\r\n})());\r\n\r\nObject.extend(Event, Event.Methods);\r\n\r\nElement.addMethods({\r\n  fire:          Event.fire,\r\n  observe:       Event.observe,\r\n  stopObserving: Event.stopObserving\r\n});\r\n\r\nObject.extend(document, {\r\n  fire:          Element.Methods.fire.methodize(),\r\n  observe:       Element.Methods.observe.methodize(),\r\n  stopObserving: Element.Methods.stopObserving.methodize(),\r\n  loaded:        false\r\n});\r\n\r\n(function() {\r\n  /* Support for the DOMContentLoaded event is based on work by Dan Webb,\r\n     Matthias Miller, Dean Edwards and John Resig. */\r\n\r\n  var timer;\r\n\r\n  function fireContentLoadedEvent() {\r\n    if (document.loaded) return;\r\n    if (timer) window.clearInterval(timer);\r\n    document.fire(\"dom:loaded\");\r\n    document.loaded = true;\r\n  }\r\n\r\n  if (document.addEventListener) {\r\n    if (Prototype.Browser.WebKit) {\r\n      timer = window.setInterval(function() {\r\n        if (/loaded|complete/.test(document.readyState))\r\n          fireContentLoadedEvent();\r\n      }, 0);\r\n\r\n      Event.observe(window, \"load\", fireContentLoadedEvent);\r\n\r\n    } else {\r\n      document.addEventListener(\"DOMContentLoaded\",\r\n        fireContentLoadedEvent, false);\r\n    }\r\n\r\n  } else {\r\n    document.write(\"<script id=__onDOMContentLoaded defer src=//:><\\/script>\");\r\n    $(\"__onDOMContentLoaded\").onreadystatechange = function() {\r\n      if (this.readyState == \"complete\") {\r\n        this.onreadystatechange = null;\r\n        fireContentLoadedEvent();\r\n      }\r\n    };\r\n  }\r\n})();\r\n/*------------------------------- DEPRECATED -------------------------------*/\r\n\r\nHash.toQueryString = Object.toQueryString;\r\n\r\nvar Toggle = { display: Element.toggle };\r\n\r\nElement.Methods.childOf = Element.Methods.descendantOf;\r\n\r\nvar Insertion = {\r\n  Before: function(element, content) {\r\n    return Element.insert(element, {before:content});\r\n  },\r\n\r\n  Top: function(element, content) {\r\n    return Element.insert(element, {top:content});\r\n  },\r\n\r\n  Bottom: function(element, content) {\r\n    return Element.insert(element, {bottom:content});\r\n  },\r\n\r\n  After: function(element, content) {\r\n    return Element.insert(element, {after:content});\r\n  }\r\n};\r\n\r\nvar $continue = new Error('\"throw $continue\" is deprecated, use \"return\" instead');\r\n\r\n// This should be moved to script.aculo.us; notice the deprecated methods\r\n// further below, that map to the newer Element methods.\r\nvar Position = {\r\n  // set to true if needed, warning: firefox performance problems\r\n  // NOT neeeded for page scrolling, only if draggable contained in\r\n  // scrollable elements\r\n  includeScrollOffsets: false,\r\n\r\n  // must be called before calling withinIncludingScrolloffset, every time the\r\n  // page is scrolled\r\n  prepare: function() {\r\n    this.deltaX =  window.pageXOffset\r\n                || document.documentElement.scrollLeft\r\n                || document.body.scrollLeft\r\n                || 0;\r\n    this.deltaY =  window.pageYOffset\r\n                || document.documentElement.scrollTop\r\n                || document.body.scrollTop\r\n                || 0;\r\n  },\r\n\r\n  // caches x/y coordinate pair to use with overlap\r\n  within: function(element, x, y) {\r\n    if (this.includeScrollOffsets)\r\n      return this.withinIncludingScrolloffsets(element, x, y);\r\n    this.xcomp = x;\r\n    this.ycomp = y;\r\n    this.offset = Element.cumulativeOffset(element);\r\n\r\n    return (y >= this.offset[1] &&\r\n            y <  this.offset[1] + element.offsetHeight &&\r\n            x >= this.offset[0] &&\r\n            x <  this.offset[0] + element.offsetWidth);\r\n  },\r\n\r\n  withinIncludingScrolloffsets: function(element, x, y) {\r\n    var offsetcache = Element.cumulativeScrollOffset(element);\r\n\r\n    this.xcomp = x + offsetcache[0] - this.deltaX;\r\n    this.ycomp = y + offsetcache[1] - this.deltaY;\r\n    this.offset = Element.cumulativeOffset(element);\r\n\r\n    return (this.ycomp >= this.offset[1] &&\r\n            this.ycomp <  this.offset[1] + element.offsetHeight &&\r\n            this.xcomp >= this.offset[0] &&\r\n            this.xcomp <  this.offset[0] + element.offsetWidth);\r\n  },\r\n\r\n  // within must be called directly before\r\n  overlap: function(mode, element) {\r\n    if (!mode) return 0;\r\n    if (mode == 'vertical')\r\n      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /\r\n        element.offsetHeight;\r\n    if (mode == 'horizontal')\r\n      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /\r\n        element.offsetWidth;\r\n  },\r\n\r\n  // Deprecation layer -- use newer Element methods now (1.5.2).\r\n\r\n  cumulativeOffset: Element.Methods.cumulativeOffset,\r\n\r\n  positionedOffset: Element.Methods.positionedOffset,\r\n\r\n  absolutize: function(element) {\r\n    Position.prepare();\r\n    return Element.absolutize(element);\r\n  },\r\n\r\n  relativize: function(element) {\r\n    Position.prepare();\r\n    return Element.relativize(element);\r\n  },\r\n\r\n  realOffset: Element.Methods.cumulativeScrollOffset,\r\n\r\n  offsetParent: Element.Methods.getOffsetParent,\r\n\r\n  page: Element.Methods.viewportOffset,\r\n\r\n  clone: function(source, target, options) {\r\n    options = options || { };\r\n    return Element.clonePosition(target, source, options);\r\n  }\r\n};\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nif (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){\r\n  function iter(name) {\r\n    return name.blank() ? null : \"[contains(concat(' ', @class, ' '), ' \" + name + \" ')]\";\r\n  }\r\n\r\n  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?\r\n  function(element, className) {\r\n    className = className.toString().strip();\r\n    var cond = /\\s/.test(className) ? $w(className).map(iter).join('') : iter(className);\r\n    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];\r\n  } : function(element, className) {\r\n    className = className.toString().strip();\r\n    var elements = [], classNames = (/\\s/.test(className) ? $w(className) : null);\r\n    if (!classNames && !className) return elements;\r\n\r\n    var nodes = $(element).getElementsByTagName('*');\r\n    className = ' ' + className + ' ';\r\n\r\n    for (var i = 0, child, cn; child = nodes[i]; i++) {\r\n      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||\r\n          (classNames && classNames.all(function(name) {\r\n            return !name.toString().blank() && cn.include(' ' + name + ' ');\r\n          }))))\r\n        elements.push(Element.extend(child));\r\n    }\r\n    return elements;\r\n  };\r\n\r\n  return function(className, parentElement) {\r\n    return $(parentElement || document.body).getElementsByClassName(className);\r\n  };\r\n}(Element.Methods);\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nElement.ClassNames = Class.create();\r\nElement.ClassNames.prototype = {\r\n  initialize: function(element) {\r\n    this.element = $(element);\r\n  },\r\n\r\n  _each: function(iterator) {\r\n    this.element.className.split(/\\s+/).select(function(name) {\r\n      return name.length > 0;\r\n    })._each(iterator);\r\n  },\r\n\r\n  set: function(className) {\r\n    this.element.className = className;\r\n  },\r\n\r\n  add: function(classNameToAdd) {\r\n    if (this.include(classNameToAdd)) return;\r\n    this.set($A(this).concat(classNameToAdd).join(' '));\r\n  },\r\n\r\n  remove: function(classNameToRemove) {\r\n    if (!this.include(classNameToRemove)) return;\r\n    this.set($A(this).without(classNameToRemove).join(' '));\r\n  },\r\n\r\n  toString: function() {\r\n    return $A(this).join(' ');\r\n  }\r\n};\r\n\r\nObject.extend(Element.ClassNames.prototype, Enumerable);\r\n\r\n/*--------------------------------------------------------------------------*/\r\n\r\nElement.addMethods();"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.css",
    "content": "/*!\n * FullCalendar v1.6.4 Stylesheet\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n\n\n.fc {\n\tdirection: ltr;\n\ttext-align: left;\n\t}\n\t\n.fc table {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n\t}\n\t\nhtml .fc,\n.fc table {\n\tfont-size: 1em;\n\t}\n\t\n.fc td,\n.fc th {\n\tpadding: 0;\n\tvertical-align: top;\n\t}\n\n\n\n/* Header\n------------------------------------------------------------------------*/\n\n.fc-header td {\n\twhite-space: nowrap;\n\t}\n\n.fc-header-left {\n\twidth: 25%;\n\ttext-align: left;\n\t}\n\t\n.fc-header-center {\n\ttext-align: center;\n\t}\n\t\n.fc-header-right {\n\twidth: 25%;\n\ttext-align: right;\n\t}\n\t\n.fc-header-title {\n\tdisplay: inline-block;\n\tvertical-align: top;\n\t}\n\t\n.fc-header-title h2 {\n\tmargin-top: 0;\n\twhite-space: nowrap;\n\t}\n\t\n.fc .fc-header-space {\n\tpadding-left: 10px;\n\t}\n\t\n.fc-header .fc-button {\n\tmargin-bottom: 1em;\n\tvertical-align: top;\n\t}\n\t\n/* buttons edges butting together */\n\n.fc-header .fc-button {\n\tmargin-right: -1px;\n\t}\n\t\n.fc-header .fc-corner-right,  /* non-theme */\n.fc-header .ui-corner-right { /* theme */\n\tmargin-right: 0; /* back to normal */\n\t}\n\t\n/* button layering (for border precedence) */\n\t\n.fc-header .fc-state-hover,\n.fc-header .ui-state-hover {\n\tz-index: 2;\n\t}\n\t\n.fc-header .fc-state-down {\n\tz-index: 3;\n\t}\n\n.fc-header .fc-state-active,\n.fc-header .ui-state-active {\n\tz-index: 4;\n\t}\n\t\n\t\n\t\n/* Content\n------------------------------------------------------------------------*/\n\t\n.fc-content {\n\tclear: both;\n\tzoom: 1; /* for IE7, gives accurate coordinates for [un]freezeContentHeight */\n\t}\n\t\n.fc-view {\n\twidth: 100%;\n\toverflow: hidden;\n\t}\n\t\n\t\n\n/* Cell Styles\n------------------------------------------------------------------------*/\n\n.fc-widget-header,    /* <th>, usually */\n.fc-widget-content {  /* <td>, usually */\n\tborder: 1px solid #ddd;\n\t}\n\t\n.fc-state-highlight { /* <td> today cell */ /* TODO: add .fc-today to <th> */\n\tbackground: #fcf8e3;\n\t}\n\t\n.fc-cell-overlay { /* semi-transparent rectangle while dragging */\n\tbackground: #bce8f1;\n\topacity: .3;\n\tfilter: alpha(opacity=30); /* for IE */\n\t}\n\t\n\n\n/* Buttons\n------------------------------------------------------------------------*/\n\n.fc-button {\n\tposition: relative;\n\tdisplay: inline-block;\n\tpadding: 0 .6em;\n\toverflow: hidden;\n\theight: 1.9em;\n\tline-height: 1.9em;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\t}\n\t\n.fc-state-default { /* non-theme */\n\tborder: 1px solid;\n\t}\n\n.fc-state-default.fc-corner-left { /* non-theme */\n\tborder-top-left-radius: 4px;\n\tborder-bottom-left-radius: 4px;\n\t}\n\n.fc-state-default.fc-corner-right { /* non-theme */\n\tborder-top-right-radius: 4px;\n\tborder-bottom-right-radius: 4px;\n\t}\n\n/*\n\tOur default prev/next buttons use HTML entities like &lsaquo; &rsaquo; &laquo; &raquo;\n\tand we'll try to make them look good cross-browser.\n*/\n\n.fc-text-arrow {\n\tmargin: 0 .1em;\n\tfont-size: 2em;\n\tfont-family: \"Courier New\", Courier, monospace;\n\tvertical-align: baseline; /* for IE7 */\n\t}\n\n.fc-button-prev .fc-text-arrow,\n.fc-button-next .fc-text-arrow { /* for &lsaquo; &rsaquo; */\n\tfont-weight: bold;\n\t}\n\t\n/* icon (for jquery ui) */\n\t\n.fc-button .fc-icon-wrap {\n\tposition: relative;\n\tfloat: left;\n\ttop: 50%;\n\t}\n\t\n.fc-button .ui-icon {\n\tposition: relative;\n\tfloat: left;\n\tmargin-top: -50%;\n\t*margin-top: 0;\n\t*top: -50%;\n\t}\n\t\n/*\n  button states\n  borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)\n*/\n\n.fc-state-default {\n\tbackground-color: #f5f5f5;\n\tbackground-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n\tbackground-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n\tbackground-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n\tbackground-image: linear-gradient(to bottom, #ffffff, #e6e6e6);\n\tbackground-repeat: repeat-x;\n\tborder-color: #e6e6e6 #e6e6e6 #bfbfbf;\n\tborder-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n\tcolor: #333;\n\ttext-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n\tbox-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n\t}\n\n.fc-state-hover,\n.fc-state-down,\n.fc-state-active,\n.fc-state-disabled {\n\tcolor: #333333;\n\tbackground-color: #e6e6e6;\n\t}\n\n.fc-state-hover {\n\tcolor: #333333;\n\ttext-decoration: none;\n\tbackground-position: 0 -15px;\n\t-webkit-transition: background-position 0.1s linear;\n\t   -moz-transition: background-position 0.1s linear;\n\t     -o-transition: background-position 0.1s linear;\n\t        transition: background-position 0.1s linear;\n\t}\n\n.fc-state-down,\n.fc-state-active {\n\tbackground-color: #cccccc;\n\tbackground-image: none;\n\toutline: 0;\n\tbox-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n\t}\n\n.fc-state-disabled {\n\tcursor: default;\n\tbackground-image: none;\n\topacity: 0.65;\n\tfilter: alpha(opacity=65);\n\tbox-shadow: none;\n\t}\n\n\t\n\n/* Global Event Styles\n------------------------------------------------------------------------*/\n\n.fc-event-container > * {\n\tz-index: 8;\n\t}\n\n.fc-event-container > .ui-draggable-dragging,\n.fc-event-container > .ui-resizable-resizing {\n\tz-index: 9;\n\t}\n\t \n.fc-event {\n\tborder: 1px solid #3a87ad; /* default BORDER color */\n\tbackground-color: #3a87ad; /* default BACKGROUND color */\n\tcolor: #fff;               /* default TEXT color */\n\tfont-size: .85em;\n\tcursor: default;\n\t}\n\na.fc-event {\n\ttext-decoration: none;\n\t}\n\t\na.fc-event,\n.fc-event-draggable {\n\tcursor: pointer;\n\t}\n\t\n.fc-rtl .fc-event {\n\ttext-align: right;\n\t}\n\n.fc-event-inner {\n\twidth: 100%;\n\theight: 100%;\n\toverflow: hidden;\n\t}\n\t\n.fc-event-time,\n.fc-event-title {\n\tpadding: 0 1px;\n\t}\n\t\n.fc .ui-resizable-handle {\n\tdisplay: block;\n\tposition: absolute;\n\tz-index: 99999;\n\toverflow: hidden; /* hacky spaces (IE6/7) */\n\tfont-size: 300%;  /* */\n\tline-height: 50%; /* */\n\t}\n\t\n\t\n\t\n/* Horizontal Events\n------------------------------------------------------------------------*/\n\n.fc-event-hori {\n\tborder-width: 1px 0;\n\tmargin-bottom: 1px;\n\t}\n\n.fc-ltr .fc-event-hori.fc-event-start,\n.fc-rtl .fc-event-hori.fc-event-end {\n\tborder-left-width: 1px;\n\tborder-top-left-radius: 3px;\n\tborder-bottom-left-radius: 3px;\n\t}\n\n.fc-ltr .fc-event-hori.fc-event-end,\n.fc-rtl .fc-event-hori.fc-event-start {\n\tborder-right-width: 1px;\n\tborder-top-right-radius: 3px;\n\tborder-bottom-right-radius: 3px;\n\t}\n\t\n/* resizable */\n\t\n.fc-event-hori .ui-resizable-e {\n\ttop: 0           !important; /* importants override pre jquery ui 1.7 styles */\n\tright: -3px      !important;\n\twidth: 7px       !important;\n\theight: 100%     !important;\n\tcursor: e-resize;\n\t}\n\t\n.fc-event-hori .ui-resizable-w {\n\ttop: 0           !important;\n\tleft: -3px       !important;\n\twidth: 7px       !important;\n\theight: 100%     !important;\n\tcursor: w-resize;\n\t}\n\t\n.fc-event-hori .ui-resizable-handle {\n\t_padding-bottom: 14px; /* IE6 had 0 height */\n\t}\n\t\n\t\n\t\n/* Reusable Separate-border Table\n------------------------------------------------------------*/\n\ntable.fc-border-separate {\n\tborder-collapse: separate;\n\t}\n\t\n.fc-border-separate th,\n.fc-border-separate td {\n\tborder-width: 1px 0 0 1px;\n\t}\n\t\n.fc-border-separate th.fc-last,\n.fc-border-separate td.fc-last {\n\tborder-right-width: 1px;\n\t}\n\t\n.fc-border-separate tr.fc-last th,\n.fc-border-separate tr.fc-last td {\n\tborder-bottom-width: 1px;\n\t}\n\t\n.fc-border-separate tbody tr.fc-first td,\n.fc-border-separate tbody tr.fc-first th {\n\tborder-top-width: 0;\n\t}\n\t\n\t\n\n/* Month View, Basic Week View, Basic Day View\n------------------------------------------------------------------------*/\n\n.fc-grid th {\n\ttext-align: center;\n\t}\n\n.fc .fc-week-number {\n\twidth: 22px;\n\ttext-align: center;\n\t}\n\n.fc .fc-week-number div {\n\tpadding: 0 2px;\n\t}\n\t\n.fc-grid .fc-day-number {\n\tfloat: right;\n\tpadding: 0 2px;\n\t}\n\t\n.fc-grid .fc-other-month .fc-day-number {\n\topacity: 0.3;\n\tfilter: alpha(opacity=30); /* for IE */\n\t/* opacity with small font can sometimes look too faded\n\t   might want to set the 'color' property instead\n\t   making day-numbers bold also fixes the problem */\n\t}\n\t\n.fc-grid .fc-day-content {\n\tclear: both;\n\tpadding: 2px 2px 1px; /* distance between events and day edges */\n\t}\n\t\n/* event styles */\n\t\n.fc-grid .fc-event-time {\n\tfont-weight: bold;\n\t}\n\t\n/* right-to-left */\n\t\n.fc-rtl .fc-grid .fc-day-number {\n\tfloat: left;\n\t}\n\t\n.fc-rtl .fc-grid .fc-event-time {\n\tfloat: right;\n\t}\n\t\n\t\n\n/* Agenda Week View, Agenda Day View\n------------------------------------------------------------------------*/\n\n.fc-agenda table {\n\tborder-collapse: separate;\n\t}\n\t\n.fc-agenda-days th {\n\ttext-align: center;\n\t}\n\t\n.fc-agenda .fc-agenda-axis {\n\twidth: 50px;\n\tpadding: 0 4px;\n\tvertical-align: middle;\n\ttext-align: right;\n\twhite-space: nowrap;\n\tfont-weight: normal;\n\t}\n\n.fc-agenda .fc-week-number {\n\tfont-weight: bold;\n\t}\n\t\n.fc-agenda .fc-day-content {\n\tpadding: 2px 2px 1px;\n\t}\n\t\n/* make axis border take precedence */\n\t\n.fc-agenda-days .fc-agenda-axis {\n\tborder-right-width: 1px;\n\t}\n\t\n.fc-agenda-days .fc-col0 {\n\tborder-left-width: 0;\n\t}\n\t\n/* all-day area */\n\t\n.fc-agenda-allday th {\n\tborder-width: 0 1px;\n\t}\n\t\n.fc-agenda-allday .fc-day-content {\n\tmin-height: 34px; /* TODO: doesnt work well in quirksmode */\n\t_height: 34px;\n\t}\n\t\n/* divider (between all-day and slots) */\n\t\n.fc-agenda-divider-inner {\n\theight: 2px;\n\toverflow: hidden;\n\t}\n\t\n.fc-widget-header .fc-agenda-divider-inner {\n\tbackground: #eee;\n\t}\n\t\n/* slot rows */\n\t\n.fc-agenda-slots th {\n\tborder-width: 1px 1px 0;\n\t}\n\t\n.fc-agenda-slots td {\n\tborder-width: 1px 0 0;\n\tbackground: none;\n\t}\n\t\n.fc-agenda-slots td div {\n\theight: 20px;\n\t}\n\t\n.fc-agenda-slots tr.fc-slot0 th,\n.fc-agenda-slots tr.fc-slot0 td {\n\tborder-top-width: 0;\n\t}\n\n.fc-agenda-slots tr.fc-minor th,\n.fc-agenda-slots tr.fc-minor td {\n\tborder-top-style: dotted;\n\t}\n\t\n.fc-agenda-slots tr.fc-minor th.ui-widget-header {\n\t*border-top-style: solid; /* doesn't work with background in IE6/7 */\n\t}\n\t\n\n\n/* Vertical Events\n------------------------------------------------------------------------*/\n\n.fc-event-vert {\n\tborder-width: 0 1px;\n\t}\n\n.fc-event-vert.fc-event-start {\n\tborder-top-width: 1px;\n\tborder-top-left-radius: 3px;\n\tborder-top-right-radius: 3px;\n\t}\n\n.fc-event-vert.fc-event-end {\n\tborder-bottom-width: 1px;\n\tborder-bottom-left-radius: 3px;\n\tborder-bottom-right-radius: 3px;\n\t}\n\t\n.fc-event-vert .fc-event-time {\n\twhite-space: nowrap;\n\tfont-size: 10px;\n\t}\n\n.fc-event-vert .fc-event-inner {\n\tposition: relative;\n\tz-index: 2;\n\t}\n\t\n.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay  */\n\tposition: absolute;\n\tz-index: 1;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: #fff;\n\topacity: .25;\n\tfilter: alpha(opacity=25);\n\t}\n\t\n.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */\n.fc-select-helper .fc-event-bg {\n\tdisplay: none\\9; /* for IE6/7/8. nested opacity filters while dragging don't work */\n\t}\n\t\n/* resizable */\n\t\n.fc-event-vert .ui-resizable-s {\n\tbottom: 0        !important; /* importants override pre jquery ui 1.7 styles */\n\twidth: 100%      !important;\n\theight: 8px      !important;\n\toverflow: hidden !important;\n\tline-height: 8px !important;\n\tfont-size: 11px  !important;\n\tfont-family: monospace;\n\ttext-align: center;\n\tcursor: s-resize;\n\t}\n\t\n.fc-agenda .ui-resizable-resizing { /* TODO: better selector */\n\t_overflow: hidden;\n\t}\n\t\n\t\n"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.js",
    "content": "/*!\n * FullCalendar v1.6.4\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n\n/*\n * Use fullcalendar.css for basic styling.\n * For event drag & drop, requires jQuery UI draggable.\n * For event resizing, requires jQuery UI resizable.\n */\n \n(function($, undefined) {\n\n\n;;\n\nvar defaults = {\n\n\t// display\n\tdefaultView: 'month',\n\taspectRatio: 1.35,\n\theader: {\n\t\tleft: 'title',\n\t\tcenter: '',\n\t\tright: 'today prev,next'\n\t},\n\tweekends: true,\n\tweekNumbers: false,\n\tweekNumberCalculation: 'iso',\n\tweekNumberTitle: 'W',\n\t\n\t// editing\n\t//editable: false,\n\t//disableDragging: false,\n\t//disableResizing: false,\n\t\n\tallDayDefault: true,\n\tignoreTimezone: true,\n\t\n\t// event ajax\n\tlazyFetching: true,\n\tstartParam: 'start',\n\tendParam: 'end',\n\t\n\t// time formats\n\ttitleFormat: {\n\t\tmonth: 'MMMM yyyy',\n\t\tweek: \"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}\",\n\t\tday: 'dddd, MMM d, yyyy'\n\t},\n\tcolumnFormat: {\n\t\tmonth: 'ddd',\n\t\tweek: 'ddd M/d',\n\t\tday: 'dddd M/d'\n\t},\n\ttimeFormat: { // for event elements\n\t\t'': 'h(:mm)t' // default\n\t},\n\t\n\t// locale\n\tisRTL: false,\n\tfirstDay: 0,\n\tmonthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],\n\tmonthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],\n\tdayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],\n\tdayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],\n\tbuttonText: {\n\t\tprev: \"<span class='fc-text-arrow'>&lsaquo;</span>\",\n\t\tnext: \"<span class='fc-text-arrow'>&rsaquo;</span>\",\n\t\tprevYear: \"<span class='fc-text-arrow'>&laquo;</span>\",\n\t\tnextYear: \"<span class='fc-text-arrow'>&raquo;</span>\",\n\t\ttoday: 'today',\n\t\tmonth: 'month',\n\t\tweek: 'week',\n\t\tday: 'day'\n\t},\n\t\n\t// jquery-ui theming\n\ttheme: false,\n\tbuttonIcons: {\n\t\tprev: 'circle-triangle-w',\n\t\tnext: 'circle-triangle-e'\n\t},\n\t\n\t//selectable: false,\n\tunselectAuto: true,\n\t\n\tdropAccept: '*',\n\t\n\thandleWindowResize: true\n\t\n};\n\n// right-to-left defaults\nvar rtlDefaults = {\n\theader: {\n\t\tleft: 'next,prev today',\n\t\tcenter: '',\n\t\tright: 'title'\n\t},\n\tbuttonText: {\n\t\tprev: \"<span class='fc-text-arrow'>&rsaquo;</span>\",\n\t\tnext: \"<span class='fc-text-arrow'>&lsaquo;</span>\",\n\t\tprevYear: \"<span class='fc-text-arrow'>&raquo;</span>\",\n\t\tnextYear: \"<span class='fc-text-arrow'>&laquo;</span>\"\n\t},\n\tbuttonIcons: {\n\t\tprev: 'circle-triangle-e',\n\t\tnext: 'circle-triangle-w'\n\t}\n};\n\n\n\n;;\n\nvar fc = $.fullCalendar = { version: \"1.6.4\" };\nvar fcViews = fc.views = {};\n\n\n$.fn.fullCalendar = function(options) {\n\n\n\t// method calling\n\tif (typeof options == 'string') {\n\t\tvar args = Array.prototype.slice.call(arguments, 1);\n\t\tvar res;\n\t\tthis.each(function() {\n\t\t\tvar calendar = $.data(this, 'fullCalendar');\n\t\t\tif (calendar && $.isFunction(calendar[options])) {\n\t\t\t\tvar r = calendar[options].apply(calendar, args);\n\t\t\t\tif (res === undefined) {\n\t\t\t\t\tres = r;\n\t\t\t\t}\n\t\t\t\tif (options == 'destroy') {\n\t\t\t\t\t$.removeData(this, 'fullCalendar');\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (res !== undefined) {\n\t\t\treturn res;\n\t\t}\n\t\treturn this;\n\t}\n\n\toptions = options || {};\n\t\n\t// would like to have this logic in EventManager, but needs to happen before options are recursively extended\n\tvar eventSources = options.eventSources || [];\n\tdelete options.eventSources;\n\tif (options.events) {\n\t\teventSources.push(options.events);\n\t\tdelete options.events;\n\t}\n\t\n\n\toptions = $.extend(true, {},\n\t\tdefaults,\n\t\t(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},\n\t\toptions\n\t);\n\t\n\t\n\tthis.each(function(i, _element) {\n\t\tvar element = $(_element);\n\t\tvar calendar = new Calendar(element, options, eventSources);\n\t\telement.data('fullCalendar', calendar); // TODO: look into memory leak implications\n\t\tcalendar.render();\n\t});\n\t\n\t\n\treturn this;\n\t\n};\n\n\n// function for adding/overriding defaults\nfunction setDefaults(d) {\n\t$.extend(true, defaults, d);\n}\n\n\n\n;;\n\n \nfunction Calendar(element, options, eventSources) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.options = options;\n\tt.render = render;\n\tt.destroy = destroy;\n\tt.refetchEvents = refetchEvents;\n\tt.reportEvents = reportEvents;\n\tt.reportEventChange = reportEventChange;\n\tt.rerenderEvents = rerenderEvents;\n\tt.changeView = changeView;\n\tt.select = select;\n\tt.unselect = unselect;\n\tt.prev = prev;\n\tt.next = next;\n\tt.prevYear = prevYear;\n\tt.nextYear = nextYear;\n\tt.today = today;\n\tt.gotoDate = gotoDate;\n\tt.incrementDate = incrementDate;\n\tt.formatDate = function(format, date) { return formatDate(format, date, options) };\n\tt.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };\n\tt.getDate = getDate;\n\tt.getView = getView;\n\tt.option = option;\n\tt.trigger = trigger;\n\t\n\t\n\t// imports\n\tEventManager.call(t, options, eventSources);\n\tvar isFetchNeeded = t.isFetchNeeded;\n\tvar fetchEvents = t.fetchEvents;\n\t\n\t\n\t// locals\n\tvar _element = element[0];\n\tvar header;\n\tvar headerElement;\n\tvar content;\n\tvar tm; // for making theme classes\n\tvar currentView;\n\tvar elementOuterWidth;\n\tvar suggestedViewHeight;\n\tvar resizeUID = 0;\n\tvar ignoreWindowResize = 0;\n\tvar date = new Date();\n\tvar events = [];\n\tvar _dragElement;\n\t\n\t\n\t\n\t/* Main Rendering\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tsetYMD(date, options.year, options.month, options.date);\n\t\n\t\n\tfunction render(inc) {\n\t\tif (!content) {\n\t\t\tinitialRender();\n\t\t}\n\t\telse if (elementVisible()) {\n\t\t\t// mainly for the public API\n\t\t\tcalcSize();\n\t\t\t_renderView(inc);\n\t\t}\n\t}\n\t\n\t\n\tfunction initialRender() {\n\t\ttm = options.theme ? 'ui' : 'fc';\n\t\telement.addClass('fc');\n\t\tif (options.isRTL) {\n\t\t\telement.addClass('fc-rtl');\n\t\t}\n\t\telse {\n\t\t\telement.addClass('fc-ltr');\n\t\t}\n\t\tif (options.theme) {\n\t\t\telement.addClass('ui-widget');\n\t\t}\n\n\t\tcontent = $(\"<div class='fc-content' style='position:relative'/>\")\n\t\t\t.prependTo(element);\n\n\t\theader = new Header(t, options);\n\t\theaderElement = header.render();\n\t\tif (headerElement) {\n\t\t\telement.prepend(headerElement);\n\t\t}\n\n\t\tchangeView(options.defaultView);\n\n\t\tif (options.handleWindowResize) {\n\t\t\t$(window).resize(windowResize);\n\t\t}\n\n\t\t// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize\n\t\tif (!bodyVisible()) {\n\t\t\tlateRender();\n\t\t}\n\t}\n\t\n\t\n\t// called when we know the calendar couldn't be rendered when it was initialized,\n\t// but we think it's ready now\n\tfunction lateRender() {\n\t\tsetTimeout(function() { // IE7 needs this so dimensions are calculated correctly\n\t\t\tif (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once\n\t\t\t\trenderView();\n\t\t\t}\n\t\t},0);\n\t}\n\t\n\t\n\tfunction destroy() {\n\n\t\tif (currentView) {\n\t\t\ttrigger('viewDestroy', currentView, currentView, currentView.element);\n\t\t\tcurrentView.triggerEventDestroy();\n\t\t}\n\n\t\t$(window).unbind('resize', windowResize);\n\n\t\theader.destroy();\n\t\tcontent.remove();\n\t\telement.removeClass('fc fc-rtl ui-widget');\n\t}\n\t\n\t\n\tfunction elementVisible() {\n\t\treturn element.is(':visible');\n\t}\n\t\n\t\n\tfunction bodyVisible() {\n\t\treturn $('body').is(':visible');\n\t}\n\t\n\t\n\t\n\t/* View Rendering\n\t-----------------------------------------------------------------------------*/\n\t\n\n\tfunction changeView(newViewName) {\n\t\tif (!currentView || newViewName != currentView.name) {\n\t\t\t_changeView(newViewName);\n\t\t}\n\t}\n\n\n\tfunction _changeView(newViewName) {\n\t\tignoreWindowResize++;\n\n\t\tif (currentView) {\n\t\t\ttrigger('viewDestroy', currentView, currentView, currentView.element);\n\t\t\tunselect();\n\t\t\tcurrentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event\n\t\t\tfreezeContentHeight();\n\t\t\tcurrentView.element.remove();\n\t\t\theader.deactivateButton(currentView.name);\n\t\t}\n\n\t\theader.activateButton(newViewName);\n\n\t\tcurrentView = new fcViews[newViewName](\n\t\t\t$(\"<div class='fc-view fc-view-\" + newViewName + \"' style='position:relative'/>\")\n\t\t\t\t.appendTo(content),\n\t\t\tt // the calendar object\n\t\t);\n\n\t\trenderView();\n\t\tunfreezeContentHeight();\n\n\t\tignoreWindowResize--;\n\t}\n\n\n\tfunction renderView(inc) {\n\t\tif (\n\t\t\t!currentView.start || // never rendered before\n\t\t\tinc || date < currentView.start || date >= currentView.end // or new date range\n\t\t) {\n\t\t\tif (elementVisible()) {\n\t\t\t\t_renderView(inc);\n\t\t\t}\n\t\t}\n\t}\n\n\n\tfunction _renderView(inc) { // assumes elementVisible\n\t\tignoreWindowResize++;\n\n\t\tif (currentView.start) { // already been rendered?\n\t\t\ttrigger('viewDestroy', currentView, currentView, currentView.element);\n\t\t\tunselect();\n\t\t\tclearEvents();\n\t\t}\n\n\t\tfreezeContentHeight();\n\t\tcurrentView.render(date, inc || 0); // the view's render method ONLY renders the skeleton, nothing else\n\t\tsetSize();\n\t\tunfreezeContentHeight();\n\t\t(currentView.afterRender || noop)();\n\n\t\tupdateTitle();\n\t\tupdateTodayButton();\n\n\t\ttrigger('viewRender', currentView, currentView, currentView.element);\n\t\tcurrentView.trigger('viewDisplay', _element); // deprecated\n\n\t\tignoreWindowResize--;\n\n\t\tgetAndRenderEvents();\n\t}\n\t\n\t\n\n\t/* Resizing\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction updateSize() {\n\t\tif (elementVisible()) {\n\t\t\tunselect();\n\t\t\tclearEvents();\n\t\t\tcalcSize();\n\t\t\tsetSize();\n\t\t\trenderEvents();\n\t\t}\n\t}\n\t\n\t\n\tfunction calcSize() { // assumes elementVisible\n\t\tif (options.contentHeight) {\n\t\t\tsuggestedViewHeight = options.contentHeight;\n\t\t}\n\t\telse if (options.height) {\n\t\t\tsuggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content);\n\t\t}\n\t\telse {\n\t\t\tsuggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));\n\t\t}\n\t}\n\t\n\t\n\tfunction setSize() { // assumes elementVisible\n\n\t\tif (suggestedViewHeight === undefined) {\n\t\t\tcalcSize(); // for first time\n\t\t\t\t// NOTE: we don't want to recalculate on every renderView because\n\t\t\t\t// it could result in oscillating heights due to scrollbars.\n\t\t}\n\n\t\tignoreWindowResize++;\n\t\tcurrentView.setHeight(suggestedViewHeight);\n\t\tcurrentView.setWidth(content.width());\n\t\tignoreWindowResize--;\n\n\t\telementOuterWidth = element.outerWidth();\n\t}\n\t\n\t\n\tfunction windowResize() {\n\t\tif (!ignoreWindowResize) {\n\t\t\tif (currentView.start) { // view has already been rendered\n\t\t\t\tvar uid = ++resizeUID;\n\t\t\t\tsetTimeout(function() { // add a delay\n\t\t\t\t\tif (uid == resizeUID && !ignoreWindowResize && elementVisible()) {\n\t\t\t\t\t\tif (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {\n\t\t\t\t\t\t\tignoreWindowResize++; // in case the windowResize callback changes the height\n\t\t\t\t\t\t\tupdateSize();\n\t\t\t\t\t\t\tcurrentView.trigger('windowResize', _element);\n\t\t\t\t\t\t\tignoreWindowResize--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 200);\n\t\t\t}else{\n\t\t\t\t// calendar must have been initialized in a 0x0 iframe that has just been resized\n\t\t\t\tlateRender();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Event Fetching/Rendering\n\t-----------------------------------------------------------------------------*/\n\t// TODO: going forward, most of this stuff should be directly handled by the view\n\n\n\tfunction refetchEvents() { // can be called as an API method\n\t\tclearEvents();\n\t\tfetchAndRenderEvents();\n\t}\n\n\n\tfunction rerenderEvents(modifiedEventID) { // can be called as an API method\n\t\tclearEvents();\n\t\trenderEvents(modifiedEventID);\n\t}\n\n\n\tfunction renderEvents(modifiedEventID) { // TODO: remove modifiedEventID hack\n\t\tif (elementVisible()) {\n\t\t\tcurrentView.setEventData(events); // for View.js, TODO: unify with renderEvents\n\t\t\tcurrentView.renderEvents(events, modifiedEventID); // actually render the DOM elements\n\t\t\tcurrentView.trigger('eventAfterAllRender');\n\t\t}\n\t}\n\n\n\tfunction clearEvents() {\n\t\tcurrentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event\n\t\tcurrentView.clearEvents(); // actually remove the DOM elements\n\t\tcurrentView.clearEventData(); // for View.js, TODO: unify with clearEvents\n\t}\n\t\n\n\tfunction getAndRenderEvents() {\n\t\tif (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {\n\t\t\tfetchAndRenderEvents();\n\t\t}\n\t\telse {\n\t\t\trenderEvents();\n\t\t}\n\t}\n\n\n\tfunction fetchAndRenderEvents() {\n\t\tfetchEvents(currentView.visStart, currentView.visEnd);\n\t\t\t// ... will call reportEvents\n\t\t\t// ... which will call renderEvents\n\t}\n\n\t\n\t// called when event data arrives\n\tfunction reportEvents(_events) {\n\t\tevents = _events;\n\t\trenderEvents();\n\t}\n\n\n\t// called when a single event's data has been changed\n\tfunction reportEventChange(eventID) {\n\t\trerenderEvents(eventID);\n\t}\n\n\n\n\t/* Header Updating\n\t-----------------------------------------------------------------------------*/\n\n\n\tfunction updateTitle() {\n\t\theader.updateTitle(currentView.title);\n\t}\n\n\n\tfunction updateTodayButton() {\n\t\tvar today = new Date();\n\t\tif (today >= currentView.start && today < currentView.end) {\n\t\t\theader.disableButton('today');\n\t\t}\n\t\telse {\n\t\t\theader.enableButton('today');\n\t\t}\n\t}\n\t\n\n\n\t/* Selection\n\t-----------------------------------------------------------------------------*/\n\t\n\n\tfunction select(start, end, allDay) {\n\t\tcurrentView.select(start, end, allDay===undefined ? true : allDay);\n\t}\n\t\n\n\tfunction unselect() { // safe to be called before renderView\n\t\tif (currentView) {\n\t\t\tcurrentView.unselect();\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Date\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction prev() {\n\t\trenderView(-1);\n\t}\n\t\n\t\n\tfunction next() {\n\t\trenderView(1);\n\t}\n\t\n\t\n\tfunction prevYear() {\n\t\taddYears(date, -1);\n\t\trenderView();\n\t}\n\t\n\t\n\tfunction nextYear() {\n\t\taddYears(date, 1);\n\t\trenderView();\n\t}\n\t\n\t\n\tfunction today() {\n\t\tdate = new Date();\n\t\trenderView();\n\t}\n\t\n\t\n\tfunction gotoDate(year, month, dateOfMonth) {\n\t\tif (year instanceof Date) {\n\t\t\tdate = cloneDate(year); // provided 1 argument, a Date\n\t\t}else{\n\t\t\tsetYMD(date, year, month, dateOfMonth);\n\t\t}\n\t\trenderView();\n\t}\n\t\n\t\n\tfunction incrementDate(years, months, days) {\n\t\tif (years !== undefined) {\n\t\t\taddYears(date, years);\n\t\t}\n\t\tif (months !== undefined) {\n\t\t\taddMonths(date, months);\n\t\t}\n\t\tif (days !== undefined) {\n\t\t\taddDays(date, days);\n\t\t}\n\t\trenderView();\n\t}\n\t\n\t\n\tfunction getDate() {\n\t\treturn cloneDate(date);\n\t}\n\n\n\n\t/* Height \"Freezing\"\n\t-----------------------------------------------------------------------------*/\n\n\n\tfunction freezeContentHeight() {\n\t\tcontent.css({\n\t\t\twidth: '100%',\n\t\t\theight: content.height(),\n\t\t\toverflow: 'hidden'\n\t\t});\n\t}\n\n\n\tfunction unfreezeContentHeight() {\n\t\tcontent.css({\n\t\t\twidth: '',\n\t\t\theight: '',\n\t\t\toverflow: ''\n\t\t});\n\t}\n\t\n\t\n\t\n\t/* Misc\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction getView() {\n\t\treturn currentView;\n\t}\n\t\n\t\n\tfunction option(name, value) {\n\t\tif (value === undefined) {\n\t\t\treturn options[name];\n\t\t}\n\t\tif (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {\n\t\t\toptions[name] = value;\n\t\t\tupdateSize();\n\t\t}\n\t}\n\t\n\t\n\tfunction trigger(name, thisObj) {\n\t\tif (options[name]) {\n\t\t\treturn options[name].apply(\n\t\t\t\tthisObj || _element,\n\t\t\t\tArray.prototype.slice.call(arguments, 2)\n\t\t\t);\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* External Dragging\n\t------------------------------------------------------------------------*/\n\t\n\tif (options.droppable) {\n\t\t$(document)\n\t\t\t.bind('dragstart', function(ev, ui) {\n\t\t\t\tvar _e = ev.target;\n\t\t\t\tvar e = $(_e);\n\t\t\t\tif (!e.parents('.fc').length) { // not already inside a calendar\n\t\t\t\t\tvar accept = options.dropAccept;\n\t\t\t\t\tif ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {\n\t\t\t\t\t\t_dragElement = _e;\n\t\t\t\t\t\tcurrentView.dragStart(_dragElement, ev, ui);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.bind('dragstop', function(ev, ui) {\n\t\t\t\tif (_dragElement) {\n\t\t\t\t\tcurrentView.dragStop(_dragElement, ev, ui);\n\t\t\t\t\t_dragElement = null;\n\t\t\t\t}\n\t\t\t});\n\t}\n\t\n\n}\n\n;;\n\nfunction Header(calendar, options) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\tt.destroy = destroy;\n\tt.updateTitle = updateTitle;\n\tt.activateButton = activateButton;\n\tt.deactivateButton = deactivateButton;\n\tt.disableButton = disableButton;\n\tt.enableButton = enableButton;\n\t\n\t\n\t// locals\n\tvar element = $([]);\n\tvar tm;\n\t\n\n\n\tfunction render() {\n\t\ttm = options.theme ? 'ui' : 'fc';\n\t\tvar sections = options.header;\n\t\tif (sections) {\n\t\t\telement = $(\"<table class='fc-header' style='width:100%'/>\")\n\t\t\t\t.append(\n\t\t\t\t\t$(\"<tr/>\")\n\t\t\t\t\t\t.append(renderSection('left'))\n\t\t\t\t\t\t.append(renderSection('center'))\n\t\t\t\t\t\t.append(renderSection('right'))\n\t\t\t\t);\n\t\t\treturn element;\n\t\t}\n\t}\n\t\n\t\n\tfunction destroy() {\n\t\telement.remove();\n\t}\n\t\n\t\n\tfunction renderSection(position) {\n\t\tvar e = $(\"<td class='fc-header-\" + position + \"'/>\");\n\t\tvar buttonStr = options.header[position];\n\t\tif (buttonStr) {\n\t\t\t$.each(buttonStr.split(' '), function(i) {\n\t\t\t\tif (i > 0) {\n\t\t\t\t\te.append(\"<span class='fc-header-space'/>\");\n\t\t\t\t}\n\t\t\t\tvar prevButton;\n\t\t\t\t$.each(this.split(','), function(j, buttonName) {\n\t\t\t\t\tif (buttonName == 'title') {\n\t\t\t\t\t\te.append(\"<span class='fc-header-title'><h2>&nbsp;</h2></span>\");\n\t\t\t\t\t\tif (prevButton) {\n\t\t\t\t\t\t\tprevButton.addClass(tm + '-corner-right');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprevButton = null;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tvar buttonClick;\n\t\t\t\t\t\tif (calendar[buttonName]) {\n\t\t\t\t\t\t\tbuttonClick = calendar[buttonName]; // calendar method\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (fcViews[buttonName]) {\n\t\t\t\t\t\t\tbuttonClick = function() {\n\t\t\t\t\t\t\t\tbutton.removeClass(tm + '-state-hover'); // forget why\n\t\t\t\t\t\t\t\tcalendar.changeView(buttonName);\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (buttonClick) {\n\t\t\t\t\t\t\tvar icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?\n\t\t\t\t\t\t\tvar text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?\n\t\t\t\t\t\t\tvar button = $(\n\t\t\t\t\t\t\t\t\"<span class='fc-button fc-button-\" + buttonName + \" \" + tm + \"-state-default'>\" +\n\t\t\t\t\t\t\t\t\t(icon ?\n\t\t\t\t\t\t\t\t\t\t\"<span class='fc-icon-wrap'>\" +\n\t\t\t\t\t\t\t\t\t\t\t\"<span class='ui-icon ui-icon-\" + icon + \"'/>\" +\n\t\t\t\t\t\t\t\t\t\t\"</span>\" :\n\t\t\t\t\t\t\t\t\t\ttext\n\t\t\t\t\t\t\t\t\t\t) +\n\t\t\t\t\t\t\t\t\"</span>\"\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.click(function() {\n\t\t\t\t\t\t\t\t\tif (!button.hasClass(tm + '-state-disabled')) {\n\t\t\t\t\t\t\t\t\t\tbuttonClick();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.mousedown(function() {\n\t\t\t\t\t\t\t\t\tbutton\n\t\t\t\t\t\t\t\t\t\t.not('.' + tm + '-state-active')\n\t\t\t\t\t\t\t\t\t\t.not('.' + tm + '-state-disabled')\n\t\t\t\t\t\t\t\t\t\t.addClass(tm + '-state-down');\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.mouseup(function() {\n\t\t\t\t\t\t\t\t\tbutton.removeClass(tm + '-state-down');\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.hover(\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\tbutton\n\t\t\t\t\t\t\t\t\t\t\t.not('.' + tm + '-state-active')\n\t\t\t\t\t\t\t\t\t\t\t.not('.' + tm + '-state-disabled')\n\t\t\t\t\t\t\t\t\t\t\t.addClass(tm + '-state-hover');\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\tbutton\n\t\t\t\t\t\t\t\t\t\t\t.removeClass(tm + '-state-hover')\n\t\t\t\t\t\t\t\t\t\t\t.removeClass(tm + '-state-down');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.appendTo(e);\n\t\t\t\t\t\t\tdisableTextSelection(button);\n\t\t\t\t\t\t\tif (!prevButton) {\n\t\t\t\t\t\t\t\tbutton.addClass(tm + '-corner-left');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tprevButton = button;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tif (prevButton) {\n\t\t\t\t\tprevButton.addClass(tm + '-corner-right');\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn e;\n\t}\n\t\n\t\n\tfunction updateTitle(html) {\n\t\telement.find('h2')\n\t\t\t.html(html);\n\t}\n\t\n\t\n\tfunction activateButton(buttonName) {\n\t\telement.find('span.fc-button-' + buttonName)\n\t\t\t.addClass(tm + '-state-active');\n\t}\n\t\n\t\n\tfunction deactivateButton(buttonName) {\n\t\telement.find('span.fc-button-' + buttonName)\n\t\t\t.removeClass(tm + '-state-active');\n\t}\n\t\n\t\n\tfunction disableButton(buttonName) {\n\t\telement.find('span.fc-button-' + buttonName)\n\t\t\t.addClass(tm + '-state-disabled');\n\t}\n\t\n\t\n\tfunction enableButton(buttonName) {\n\t\telement.find('span.fc-button-' + buttonName)\n\t\t\t.removeClass(tm + '-state-disabled');\n\t}\n\n\n}\n\n;;\n\nfc.sourceNormalizers = [];\nfc.sourceFetchers = [];\n\nvar ajaxDefaults = {\n\tdataType: 'json',\n\tcache: false\n};\n\nvar eventGUID = 1;\n\n\nfunction EventManager(options, _sources) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.isFetchNeeded = isFetchNeeded;\n\tt.fetchEvents = fetchEvents;\n\tt.addEventSource = addEventSource;\n\tt.removeEventSource = removeEventSource;\n\tt.updateEvent = updateEvent;\n\tt.renderEvent = renderEvent;\n\tt.removeEvents = removeEvents;\n\tt.clientEvents = clientEvents;\n\tt.normalizeEvent = normalizeEvent;\n\t\n\t\n\t// imports\n\tvar trigger = t.trigger;\n\tvar getView = t.getView;\n\tvar reportEvents = t.reportEvents;\n\t\n\t\n\t// locals\n\tvar stickySource = { events: [] };\n\tvar sources = [ stickySource ];\n\tvar rangeStart, rangeEnd;\n\tvar currentFetchID = 0;\n\tvar pendingSourceCnt = 0;\n\tvar loadingLevel = 0;\n\tvar cache = [];\n\t\n\t\n\tfor (var i=0; i<_sources.length; i++) {\n\t\t_addEventSource(_sources[i]);\n\t}\n\t\n\t\n\t\n\t/* Fetching\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction isFetchNeeded(start, end) {\n\t\treturn !rangeStart || start < rangeStart || end > rangeEnd;\n\t}\n\t\n\t\n\tfunction fetchEvents(start, end) {\n\t\trangeStart = start;\n\t\trangeEnd = end;\n\t\tcache = [];\n\t\tvar fetchID = ++currentFetchID;\n\t\tvar len = sources.length;\n\t\tpendingSourceCnt = len;\n\t\tfor (var i=0; i<len; i++) {\n\t\t\tfetchEventSource(sources[i], fetchID);\n\t\t}\n\t}\n\t\n\t\n\tfunction fetchEventSource(source, fetchID) {\n\t\t_fetchEventSource(source, function(events) {\n\t\t\tif (fetchID == currentFetchID) {\n\t\t\t\tif (events) {\n\n\t\t\t\t\tif (options.eventDataTransform) {\n\t\t\t\t\t\tevents = $.map(events, options.eventDataTransform);\n\t\t\t\t\t}\n\t\t\t\t\tif (source.eventDataTransform) {\n\t\t\t\t\t\tevents = $.map(events, source.eventDataTransform);\n\t\t\t\t\t}\n\t\t\t\t\t// TODO: this technique is not ideal for static array event sources.\n\t\t\t\t\t//  For arrays, we'll want to process all events right in the beginning, then never again.\n\t\t\t\t\n\t\t\t\t\tfor (var i=0; i<events.length; i++) {\n\t\t\t\t\t\tevents[i].source = source;\n\t\t\t\t\t\tnormalizeEvent(events[i]);\n\t\t\t\t\t}\n\t\t\t\t\tcache = cache.concat(events);\n\t\t\t\t}\n\t\t\t\tpendingSourceCnt--;\n\t\t\t\tif (!pendingSourceCnt) {\n\t\t\t\t\treportEvents(cache);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\t\n\t\n\tfunction _fetchEventSource(source, callback) {\n\t\tvar i;\n\t\tvar fetchers = fc.sourceFetchers;\n\t\tvar res;\n\t\tfor (i=0; i<fetchers.length; i++) {\n\t\t\tres = fetchers[i](source, rangeStart, rangeEnd, callback);\n\t\t\tif (res === true) {\n\t\t\t\t// the fetcher is in charge. made its own async request\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (typeof res == 'object') {\n\t\t\t\t// the fetcher returned a new source. process it\n\t\t\t\t_fetchEventSource(res, callback);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tvar events = source.events;\n\t\tif (events) {\n\t\t\tif ($.isFunction(events)) {\n\t\t\t\tpushLoading();\n\t\t\t\tevents(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {\n\t\t\t\t\tcallback(events);\n\t\t\t\t\tpopLoading();\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if ($.isArray(events)) {\n\t\t\t\tcallback(events);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcallback();\n\t\t\t}\n\t\t}else{\n\t\t\tvar url = source.url;\n\t\t\tif (url) {\n\t\t\t\tvar success = source.success;\n\t\t\t\tvar error = source.error;\n\t\t\t\tvar complete = source.complete;\n\n\t\t\t\t// retrieve any outbound GET/POST $.ajax data from the options\n\t\t\t\tvar customData;\n\t\t\t\tif ($.isFunction(source.data)) {\n\t\t\t\t\t// supplied as a function that returns a key/value object\n\t\t\t\t\tcustomData = source.data();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// supplied as a straight key/value object\n\t\t\t\t\tcustomData = source.data;\n\t\t\t\t}\n\n\t\t\t\t// use a copy of the custom data so we can modify the parameters\n\t\t\t\t// and not affect the passed-in object.\n\t\t\t\tvar data = $.extend({}, customData || {});\n\n\t\t\t\tvar startParam = firstDefined(source.startParam, options.startParam);\n\t\t\t\tvar endParam = firstDefined(source.endParam, options.endParam);\n\t\t\t\tif (startParam) {\n\t\t\t\t\tdata[startParam] = Math.round(+rangeStart / 1000);\n\t\t\t\t}\n\t\t\t\tif (endParam) {\n\t\t\t\t\tdata[endParam] = Math.round(+rangeEnd / 1000);\n\t\t\t\t}\n\n\t\t\t\tpushLoading();\n\t\t\t\t$.ajax($.extend({}, ajaxDefaults, source, {\n\t\t\t\t\tdata: data,\n\t\t\t\t\tsuccess: function(events) {\n\t\t\t\t\t\tevents = events || [];\n\t\t\t\t\t\tvar res = applyAll(success, this, arguments);\n\t\t\t\t\t\tif ($.isArray(res)) {\n\t\t\t\t\t\t\tevents = res;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcallback(events);\n\t\t\t\t\t},\n\t\t\t\t\terror: function() {\n\t\t\t\t\t\tapplyAll(error, this, arguments);\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t},\n\t\t\t\t\tcomplete: function() {\n\t\t\t\t\t\tapplyAll(complete, this, arguments);\n\t\t\t\t\t\tpopLoading();\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t}else{\n\t\t\t\tcallback();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Sources\n\t-----------------------------------------------------------------------------*/\n\t\n\n\tfunction addEventSource(source) {\n\t\tsource = _addEventSource(source);\n\t\tif (source) {\n\t\t\tpendingSourceCnt++;\n\t\t\tfetchEventSource(source, currentFetchID); // will eventually call reportEvents\n\t\t}\n\t}\n\t\n\t\n\tfunction _addEventSource(source) {\n\t\tif ($.isFunction(source) || $.isArray(source)) {\n\t\t\tsource = { events: source };\n\t\t}\n\t\telse if (typeof source == 'string') {\n\t\t\tsource = { url: source };\n\t\t}\n\t\tif (typeof source == 'object') {\n\t\t\tnormalizeSource(source);\n\t\t\tsources.push(source);\n\t\t\treturn source;\n\t\t}\n\t}\n\t\n\n\tfunction removeEventSource(source) {\n\t\tsources = $.grep(sources, function(src) {\n\t\t\treturn !isSourcesEqual(src, source);\n\t\t});\n\t\t// remove all client events from that source\n\t\tcache = $.grep(cache, function(e) {\n\t\t\treturn !isSourcesEqual(e.source, source);\n\t\t});\n\t\treportEvents(cache);\n\t}\n\t\n\t\n\t\n\t/* Manipulation\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction updateEvent(event) { // update an existing event\n\t\tvar i, len = cache.length, e,\n\t\t\tdefaultEventEnd = getView().defaultEventEnd, // getView???\n\t\t\tstartDelta = event.start - event._start,\n\t\t\tendDelta = event.end ?\n\t\t\t\t(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end\n\t\t\t\t: 0;                                                      // was null and event was just resized\n\t\tfor (i=0; i<len; i++) {\n\t\t\te = cache[i];\n\t\t\tif (e._id == event._id && e != event) {\n\t\t\t\te.start = new Date(+e.start + startDelta);\n\t\t\t\tif (event.end) {\n\t\t\t\t\tif (e.end) {\n\t\t\t\t\t\te.end = new Date(+e.end + endDelta);\n\t\t\t\t\t}else{\n\t\t\t\t\t\te.end = new Date(+defaultEventEnd(e) + endDelta);\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\te.end = null;\n\t\t\t\t}\n\t\t\t\te.title = event.title;\n\t\t\t\te.url = event.url;\n\t\t\t\te.allDay = event.allDay;\n\t\t\t\te.className = event.className;\n\t\t\t\te.editable = event.editable;\n\t\t\t\te.color = event.color;\n\t\t\t\te.backgroundColor = event.backgroundColor;\n\t\t\t\te.borderColor = event.borderColor;\n\t\t\t\te.textColor = event.textColor;\n\t\t\t\tnormalizeEvent(e);\n\t\t\t}\n\t\t}\n\t\tnormalizeEvent(event);\n\t\treportEvents(cache);\n\t}\n\t\n\t\n\tfunction renderEvent(event, stick) {\n\t\tnormalizeEvent(event);\n\t\tif (!event.source) {\n\t\t\tif (stick) {\n\t\t\t\tstickySource.events.push(event);\n\t\t\t\tevent.source = stickySource;\n\t\t\t}\n\t\t\tcache.push(event);\n\t\t}\n\t\treportEvents(cache);\n\t}\n\t\n\t\n\tfunction removeEvents(filter) {\n\t\tif (!filter) { // remove all\n\t\t\tcache = [];\n\t\t\t// clear all array sources\n\t\t\tfor (var i=0; i<sources.length; i++) {\n\t\t\t\tif ($.isArray(sources[i].events)) {\n\t\t\t\t\tsources[i].events = [];\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\tif (!$.isFunction(filter)) { // an event ID\n\t\t\t\tvar id = filter + '';\n\t\t\t\tfilter = function(e) {\n\t\t\t\t\treturn e._id == id;\n\t\t\t\t};\n\t\t\t}\n\t\t\tcache = $.grep(cache, filter, true);\n\t\t\t// remove events from array sources\n\t\t\tfor (var i=0; i<sources.length; i++) {\n\t\t\t\tif ($.isArray(sources[i].events)) {\n\t\t\t\t\tsources[i].events = $.grep(sources[i].events, filter, true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treportEvents(cache);\n\t}\n\t\n\t\n\tfunction clientEvents(filter) {\n\t\tif ($.isFunction(filter)) {\n\t\t\treturn $.grep(cache, filter);\n\t\t}\n\t\telse if (filter) { // an event ID\n\t\t\tfilter += '';\n\t\t\treturn $.grep(cache, function(e) {\n\t\t\t\treturn e._id == filter;\n\t\t\t});\n\t\t}\n\t\treturn cache; // else, return all\n\t}\n\t\n\t\n\t\n\t/* Loading State\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction pushLoading() {\n\t\tif (!loadingLevel++) {\n\t\t\ttrigger('loading', null, true, getView());\n\t\t}\n\t}\n\t\n\t\n\tfunction popLoading() {\n\t\tif (!--loadingLevel) {\n\t\t\ttrigger('loading', null, false, getView());\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Event Normalization\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tfunction normalizeEvent(event) {\n\t\tvar source = event.source || {};\n\t\tvar ignoreTimezone = firstDefined(source.ignoreTimezone, options.ignoreTimezone);\n\t\tevent._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');\n\t\tif (event.date) {\n\t\t\tif (!event.start) {\n\t\t\t\tevent.start = event.date;\n\t\t\t}\n\t\t\tdelete event.date;\n\t\t}\n\t\tevent._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));\n\t\tevent.end = parseDate(event.end, ignoreTimezone);\n\t\tif (event.end && event.end <= event.start) {\n\t\t\tevent.end = null;\n\t\t}\n\t\tevent._end = event.end ? cloneDate(event.end) : null;\n\t\tif (event.allDay === undefined) {\n\t\t\tevent.allDay = firstDefined(source.allDayDefault, options.allDayDefault);\n\t\t}\n\t\tif (event.className) {\n\t\t\tif (typeof event.className == 'string') {\n\t\t\t\tevent.className = event.className.split(/\\s+/);\n\t\t\t}\n\t\t}else{\n\t\t\tevent.className = [];\n\t\t}\n\t\t// TODO: if there is no start date, return false to indicate an invalid event\n\t}\n\t\n\t\n\t\n\t/* Utils\n\t------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction normalizeSource(source) {\n\t\tif (source.className) {\n\t\t\t// TODO: repeat code, same code for event classNames\n\t\t\tif (typeof source.className == 'string') {\n\t\t\t\tsource.className = source.className.split(/\\s+/);\n\t\t\t}\n\t\t}else{\n\t\t\tsource.className = [];\n\t\t}\n\t\tvar normalizers = fc.sourceNormalizers;\n\t\tfor (var i=0; i<normalizers.length; i++) {\n\t\t\tnormalizers[i](source);\n\t\t}\n\t}\n\t\n\t\n\tfunction isSourcesEqual(source1, source2) {\n\t\treturn source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);\n\t}\n\t\n\t\n\tfunction getSourcePrimitive(source) {\n\t\treturn ((typeof source == 'object') ? (source.events || source.url) : '') || source;\n\t}\n\n\n}\n\n;;\n\n\nfc.addDays = addDays;\nfc.cloneDate = cloneDate;\nfc.parseDate = parseDate;\nfc.parseISO8601 = parseISO8601;\nfc.parseTime = parseTime;\nfc.formatDate = formatDate;\nfc.formatDates = formatDates;\n\n\n\n/* Date Math\n-----------------------------------------------------------------------------*/\n\nvar dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],\n\tDAY_MS = 86400000,\n\tHOUR_MS = 3600000,\n\tMINUTE_MS = 60000;\n\t\n\nfunction addYears(d, n, keepTime) {\n\td.setFullYear(d.getFullYear() + n);\n\tif (!keepTime) {\n\t\tclearTime(d);\n\t}\n\treturn d;\n}\n\n\nfunction addMonths(d, n, keepTime) { // prevents day overflow/underflow\n\tif (+d) { // prevent infinite looping on invalid dates\n\t\tvar m = d.getMonth() + n,\n\t\t\tcheck = cloneDate(d);\n\t\tcheck.setDate(1);\n\t\tcheck.setMonth(m);\n\t\td.setMonth(m);\n\t\tif (!keepTime) {\n\t\t\tclearTime(d);\n\t\t}\n\t\twhile (d.getMonth() != check.getMonth()) {\n\t\t\td.setDate(d.getDate() + (d < check ? 1 : -1));\n\t\t}\n\t}\n\treturn d;\n}\n\n\nfunction addDays(d, n, keepTime) { // deals with daylight savings\n\tif (+d) {\n\t\tvar dd = d.getDate() + n,\n\t\t\tcheck = cloneDate(d);\n\t\tcheck.setHours(9); // set to middle of day\n\t\tcheck.setDate(dd);\n\t\td.setDate(dd);\n\t\tif (!keepTime) {\n\t\t\tclearTime(d);\n\t\t}\n\t\tfixDate(d, check);\n\t}\n\treturn d;\n}\n\n\nfunction fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes\n\tif (+d) { // prevent infinite looping on invalid dates\n\t\twhile (d.getDate() != check.getDate()) {\n\t\t\td.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);\n\t\t}\n\t}\n}\n\n\nfunction addMinutes(d, n) {\n\td.setMinutes(d.getMinutes() + n);\n\treturn d;\n}\n\n\nfunction clearTime(d) {\n\td.setHours(0);\n\td.setMinutes(0);\n\td.setSeconds(0); \n\td.setMilliseconds(0);\n\treturn d;\n}\n\n\nfunction cloneDate(d, dontKeepTime) {\n\tif (dontKeepTime) {\n\t\treturn clearTime(new Date(+d));\n\t}\n\treturn new Date(+d);\n}\n\n\nfunction zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1\n\tvar i=0, d;\n\tdo {\n\t\td = new Date(1970, i++, 1);\n\t} while (d.getHours()); // != 0\n\treturn d;\n}\n\n\nfunction dayDiff(d1, d2) { // d1 - d2\n\treturn Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);\n}\n\n\nfunction setYMD(date, y, m, d) {\n\tif (y !== undefined && y != date.getFullYear()) {\n\t\tdate.setDate(1);\n\t\tdate.setMonth(0);\n\t\tdate.setFullYear(y);\n\t}\n\tif (m !== undefined && m != date.getMonth()) {\n\t\tdate.setDate(1);\n\t\tdate.setMonth(m);\n\t}\n\tif (d !== undefined) {\n\t\tdate.setDate(d);\n\t}\n}\n\n\n\n/* Date Parsing\n-----------------------------------------------------------------------------*/\n\n\nfunction parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true\n\tif (typeof s == 'object') { // already a Date object\n\t\treturn s;\n\t}\n\tif (typeof s == 'number') { // a UNIX timestamp\n\t\treturn new Date(s * 1000);\n\t}\n\tif (typeof s == 'string') {\n\t\tif (s.match(/^\\d+(\\.\\d+)?$/)) { // a UNIX timestamp\n\t\t\treturn new Date(parseFloat(s) * 1000);\n\t\t}\n\t\tif (ignoreTimezone === undefined) {\n\t\t\tignoreTimezone = true;\n\t\t}\n\t\treturn parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);\n\t}\n\t// TODO: never return invalid dates (like from new Date(<string>)), return null instead\n\treturn null;\n}\n\n\nfunction parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false\n\t// derived from http://delete.me.uk/2005/03/iso8601.html\n\t// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html\n\tvar m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);\n\tif (!m) {\n\t\treturn null;\n\t}\n\tvar date = new Date(m[1], 0, 1);\n\tif (ignoreTimezone || !m[13]) {\n\t\tvar check = new Date(m[1], 0, 1, 9, 0);\n\t\tif (m[3]) {\n\t\t\tdate.setMonth(m[3] - 1);\n\t\t\tcheck.setMonth(m[3] - 1);\n\t\t}\n\t\tif (m[5]) {\n\t\t\tdate.setDate(m[5]);\n\t\t\tcheck.setDate(m[5]);\n\t\t}\n\t\tfixDate(date, check);\n\t\tif (m[7]) {\n\t\t\tdate.setHours(m[7]);\n\t\t}\n\t\tif (m[8]) {\n\t\t\tdate.setMinutes(m[8]);\n\t\t}\n\t\tif (m[10]) {\n\t\t\tdate.setSeconds(m[10]);\n\t\t}\n\t\tif (m[12]) {\n\t\t\tdate.setMilliseconds(Number(\"0.\" + m[12]) * 1000);\n\t\t}\n\t\tfixDate(date, check);\n\t}else{\n\t\tdate.setUTCFullYear(\n\t\t\tm[1],\n\t\t\tm[3] ? m[3] - 1 : 0,\n\t\t\tm[5] || 1\n\t\t);\n\t\tdate.setUTCHours(\n\t\t\tm[7] || 0,\n\t\t\tm[8] || 0,\n\t\t\tm[10] || 0,\n\t\t\tm[12] ? Number(\"0.\" + m[12]) * 1000 : 0\n\t\t);\n\t\tif (m[14]) {\n\t\t\tvar offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);\n\t\t\toffset *= m[15] == '-' ? 1 : -1;\n\t\t\tdate = new Date(+date + (offset * 60 * 1000));\n\t\t}\n\t}\n\treturn date;\n}\n\n\nfunction parseTime(s) { // returns minutes since start of day\n\tif (typeof s == 'number') { // an hour\n\t\treturn s * 60;\n\t}\n\tif (typeof s == 'object') { // a Date object\n\t\treturn s.getHours() * 60 + s.getMinutes();\n\t}\n\tvar m = s.match(/(\\d+)(?::(\\d+))?\\s*(\\w+)?/);\n\tif (m) {\n\t\tvar h = parseInt(m[1], 10);\n\t\tif (m[3]) {\n\t\t\th %= 12;\n\t\t\tif (m[3].toLowerCase().charAt(0) == 'p') {\n\t\t\t\th += 12;\n\t\t\t}\n\t\t}\n\t\treturn h * 60 + (m[2] ? parseInt(m[2], 10) : 0);\n\t}\n}\n\n\n\n/* Date Formatting\n-----------------------------------------------------------------------------*/\n// TODO: use same function formatDate(date, [date2], format, [options])\n\n\nfunction formatDate(date, format, options) {\n\treturn formatDates(date, null, format, options);\n}\n\n\nfunction formatDates(date1, date2, format, options) {\n\toptions = options || defaults;\n\tvar date = date1,\n\t\totherDate = date2,\n\t\ti, len = format.length, c,\n\t\ti2, formatter,\n\t\tres = '';\n\tfor (i=0; i<len; i++) {\n\t\tc = format.charAt(i);\n\t\tif (c == \"'\") {\n\t\t\tfor (i2=i+1; i2<len; i2++) {\n\t\t\t\tif (format.charAt(i2) == \"'\") {\n\t\t\t\t\tif (date) {\n\t\t\t\t\t\tif (i2 == i+1) {\n\t\t\t\t\t\t\tres += \"'\";\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tres += format.substring(i+1, i2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ti = i2;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (c == '(') {\n\t\t\tfor (i2=i+1; i2<len; i2++) {\n\t\t\t\tif (format.charAt(i2) == ')') {\n\t\t\t\t\tvar subres = formatDate(date, format.substring(i+1, i2), options);\n\t\t\t\t\tif (parseInt(subres.replace(/\\D/, ''), 10)) {\n\t\t\t\t\t\tres += subres;\n\t\t\t\t\t}\n\t\t\t\t\ti = i2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (c == '[') {\n\t\t\tfor (i2=i+1; i2<len; i2++) {\n\t\t\t\tif (format.charAt(i2) == ']') {\n\t\t\t\t\tvar subformat = format.substring(i+1, i2);\n\t\t\t\t\tvar subres = formatDate(date, subformat, options);\n\t\t\t\t\tif (subres != formatDate(otherDate, subformat, options)) {\n\t\t\t\t\t\tres += subres;\n\t\t\t\t\t}\n\t\t\t\t\ti = i2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (c == '{') {\n\t\t\tdate = date2;\n\t\t\totherDate = date1;\n\t\t}\n\t\telse if (c == '}') {\n\t\t\tdate = date1;\n\t\t\totherDate = date2;\n\t\t}\n\t\telse {\n\t\t\tfor (i2=len; i2>i; i2--) {\n\t\t\t\tif (formatter = dateFormatters[format.substring(i, i2)]) {\n\t\t\t\t\tif (date) {\n\t\t\t\t\t\tres += formatter(date, options);\n\t\t\t\t\t}\n\t\t\t\t\ti = i2 - 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (i2 == i) {\n\t\t\t\tif (date) {\n\t\t\t\t\tres += c;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn res;\n};\n\n\nvar dateFormatters = {\n\ts\t: function(d)\t{ return d.getSeconds() },\n\tss\t: function(d)\t{ return zeroPad(d.getSeconds()) },\n\tm\t: function(d)\t{ return d.getMinutes() },\n\tmm\t: function(d)\t{ return zeroPad(d.getMinutes()) },\n\th\t: function(d)\t{ return d.getHours() % 12 || 12 },\n\thh\t: function(d)\t{ return zeroPad(d.getHours() % 12 || 12) },\n\tH\t: function(d)\t{ return d.getHours() },\n\tHH\t: function(d)\t{ return zeroPad(d.getHours()) },\n\td\t: function(d)\t{ return d.getDate() },\n\tdd\t: function(d)\t{ return zeroPad(d.getDate()) },\n\tddd\t: function(d,o)\t{ return o.dayNamesShort[d.getDay()] },\n\tdddd: function(d,o)\t{ return o.dayNames[d.getDay()] },\n\tM\t: function(d)\t{ return d.getMonth() + 1 },\n\tMM\t: function(d)\t{ return zeroPad(d.getMonth() + 1) },\n\tMMM\t: function(d,o)\t{ return o.monthNamesShort[d.getMonth()] },\n\tMMMM: function(d,o)\t{ return o.monthNames[d.getMonth()] },\n\tyy\t: function(d)\t{ return (d.getFullYear()+'').substring(2) },\n\tyyyy: function(d)\t{ return d.getFullYear() },\n\tt\t: function(d)\t{ return d.getHours() < 12 ? 'a' : 'p' },\n\ttt\t: function(d)\t{ return d.getHours() < 12 ? 'am' : 'pm' },\n\tT\t: function(d)\t{ return d.getHours() < 12 ? 'A' : 'P' },\n\tTT\t: function(d)\t{ return d.getHours() < 12 ? 'AM' : 'PM' },\n\tu\t: function(d)\t{ return formatDate(d, \"yyyy-MM-dd'T'HH:mm:ss'Z'\") },\n\tS\t: function(d)\t{\n\t\tvar date = d.getDate();\n\t\tif (date > 10 && date < 20) {\n\t\t\treturn 'th';\n\t\t}\n\t\treturn ['st', 'nd', 'rd'][date%10-1] || 'th';\n\t},\n\tw   : function(d, o) { // local\n\t\treturn o.weekNumberCalculation(d);\n\t},\n\tW   : function(d) { // ISO\n\t\treturn iso8601Week(d);\n\t}\n};\nfc.dateFormatters = dateFormatters;\n\n\n/* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js)\n * \n * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.\n * `date` - the date to get the week for\n * `number` - the number of the week within the year that contains this date\n */\nfunction iso8601Week(date) {\n\tvar time;\n\tvar checkDate = new Date(date.getTime());\n\n\t// Find Thursday of this week starting on Monday\n\tcheckDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));\n\n\ttime = checkDate.getTime();\n\tcheckDate.setMonth(0); // Compare with Jan 1\n\tcheckDate.setDate(1);\n\treturn Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;\n}\n\n\n;;\n\nfc.applyAll = applyAll;\n\n\n/* Event Date Math\n-----------------------------------------------------------------------------*/\n\n\nfunction exclEndDay(event) {\n\tif (event.end) {\n\t\treturn _exclEndDay(event.end, event.allDay);\n\t}else{\n\t\treturn addDays(cloneDate(event.start), 1);\n\t}\n}\n\n\nfunction _exclEndDay(end, allDay) {\n\tend = cloneDate(end);\n\treturn allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);\n\t// why don't we check for seconds/ms too?\n}\n\n\n\n/* Event Element Binding\n-----------------------------------------------------------------------------*/\n\n\nfunction lazySegBind(container, segs, bindHandlers) {\n\tcontainer.unbind('mouseover').mouseover(function(ev) {\n\t\tvar parent=ev.target, e,\n\t\t\ti, seg;\n\t\twhile (parent != this) {\n\t\t\te = parent;\n\t\t\tparent = parent.parentNode;\n\t\t}\n\t\tif ((i = e._fci) !== undefined) {\n\t\t\te._fci = undefined;\n\t\t\tseg = segs[i];\n\t\t\tbindHandlers(seg.event, seg.element, seg);\n\t\t\t$(ev.target).trigger(ev);\n\t\t}\n\t\tev.stopPropagation();\n\t});\n}\n\n\n\n/* Element Dimensions\n-----------------------------------------------------------------------------*/\n\n\nfunction setOuterWidth(element, width, includeMargins) {\n\tfor (var i=0, e; i<element.length; i++) {\n\t\te = $(element[i]);\n\t\te.width(Math.max(0, width - hsides(e, includeMargins)));\n\t}\n}\n\n\nfunction setOuterHeight(element, height, includeMargins) {\n\tfor (var i=0, e; i<element.length; i++) {\n\t\te = $(element[i]);\n\t\te.height(Math.max(0, height - vsides(e, includeMargins)));\n\t}\n}\n\n\nfunction hsides(element, includeMargins) {\n\treturn hpadding(element) + hborders(element) + (includeMargins ? hmargins(element) : 0);\n}\n\n\nfunction hpadding(element) {\n\treturn (parseFloat($.css(element[0], 'paddingLeft', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'paddingRight', true)) || 0);\n}\n\n\nfunction hmargins(element) {\n\treturn (parseFloat($.css(element[0], 'marginLeft', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'marginRight', true)) || 0);\n}\n\n\nfunction hborders(element) {\n\treturn (parseFloat($.css(element[0], 'borderLeftWidth', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'borderRightWidth', true)) || 0);\n}\n\n\nfunction vsides(element, includeMargins) {\n\treturn vpadding(element) +  vborders(element) + (includeMargins ? vmargins(element) : 0);\n}\n\n\nfunction vpadding(element) {\n\treturn (parseFloat($.css(element[0], 'paddingTop', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'paddingBottom', true)) || 0);\n}\n\n\nfunction vmargins(element) {\n\treturn (parseFloat($.css(element[0], 'marginTop', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'marginBottom', true)) || 0);\n}\n\n\nfunction vborders(element) {\n\treturn (parseFloat($.css(element[0], 'borderTopWidth', true)) || 0) +\n\t       (parseFloat($.css(element[0], 'borderBottomWidth', true)) || 0);\n}\n\n\n\n/* Misc Utils\n-----------------------------------------------------------------------------*/\n\n\n//TODO: arraySlice\n//TODO: isFunction, grep ?\n\n\nfunction noop() { }\n\n\nfunction dateCompare(a, b) {\n\treturn a - b;\n}\n\n\nfunction arrayMax(a) {\n\treturn Math.max.apply(Math, a);\n}\n\n\nfunction zeroPad(n) {\n\treturn (n < 10 ? '0' : '') + n;\n}\n\n\nfunction smartProperty(obj, name) { // get a camel-cased/namespaced property of an object\n\tif (obj[name] !== undefined) {\n\t\treturn obj[name];\n\t}\n\tvar parts = name.split(/(?=[A-Z])/),\n\t\ti=parts.length-1, res;\n\tfor (; i>=0; i--) {\n\t\tres = obj[parts[i].toLowerCase()];\n\t\tif (res !== undefined) {\n\t\t\treturn res;\n\t\t}\n\t}\n\treturn obj[''];\n}\n\n\nfunction htmlEscape(s) {\n\treturn s.replace(/&/g, '&amp;')\n\t\t.replace(/</g, '&lt;')\n\t\t.replace(/>/g, '&gt;')\n\t\t.replace(/'/g, '&#039;')\n\t\t.replace(/\"/g, '&quot;')\n\t\t.replace(/\\n/g, '<br />');\n}\n\n\nfunction disableTextSelection(element) {\n\telement\n\t\t.attr('unselectable', 'on')\n\t\t.css('MozUserSelect', 'none')\n\t\t.bind('selectstart.ui', function() { return false; });\n}\n\n\n/*\nfunction enableTextSelection(element) {\n\telement\n\t\t.attr('unselectable', 'off')\n\t\t.css('MozUserSelect', '')\n\t\t.unbind('selectstart.ui');\n}\n*/\n\n\nfunction markFirstLast(e) {\n\te.children()\n\t\t.removeClass('fc-first fc-last')\n\t\t.filter(':first-child')\n\t\t\t.addClass('fc-first')\n\t\t.end()\n\t\t.filter(':last-child')\n\t\t\t.addClass('fc-last');\n}\n\n\nfunction setDayID(cell, date) {\n\tcell.each(function(i, _cell) {\n\t\t_cell.className = _cell.className.replace(/^fc-\\w*/, 'fc-' + dayIDs[date.getDay()]);\n\t\t// TODO: make a way that doesn't rely on order of classes\n\t});\n}\n\n\nfunction getSkinCss(event, opt) {\n\tvar source = event.source || {};\n\tvar eventColor = event.color;\n\tvar sourceColor = source.color;\n\tvar optionColor = opt('eventColor');\n\tvar backgroundColor =\n\t\tevent.backgroundColor ||\n\t\teventColor ||\n\t\tsource.backgroundColor ||\n\t\tsourceColor ||\n\t\topt('eventBackgroundColor') ||\n\t\toptionColor;\n\tvar borderColor =\n\t\tevent.borderColor ||\n\t\teventColor ||\n\t\tsource.borderColor ||\n\t\tsourceColor ||\n\t\topt('eventBorderColor') ||\n\t\toptionColor;\n\tvar textColor =\n\t\tevent.textColor ||\n\t\tsource.textColor ||\n\t\topt('eventTextColor');\n\tvar statements = [];\n\tif (backgroundColor) {\n\t\tstatements.push('background-color:' + backgroundColor);\n\t}\n\tif (borderColor) {\n\t\tstatements.push('border-color:' + borderColor);\n\t}\n\tif (textColor) {\n\t\tstatements.push('color:' + textColor);\n\t}\n\treturn statements.join(';');\n}\n\n\nfunction applyAll(functions, thisObj, args) {\n\tif ($.isFunction(functions)) {\n\t\tfunctions = [ functions ];\n\t}\n\tif (functions) {\n\t\tvar i;\n\t\tvar ret;\n\t\tfor (i=0; i<functions.length; i++) {\n\t\t\tret = functions[i].apply(thisObj, args) || ret;\n\t\t}\n\t\treturn ret;\n\t}\n}\n\n\nfunction firstDefined() {\n\tfor (var i=0; i<arguments.length; i++) {\n\t\tif (arguments[i] !== undefined) {\n\t\t\treturn arguments[i];\n\t\t}\n\t}\n}\n\n\n;;\n\nfcViews.month = MonthView;\n\nfunction MonthView(element, calendar) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\t\n\t\n\t// imports\n\tBasicView.call(t, element, calendar, 'month');\n\tvar opt = t.opt;\n\tvar renderBasic = t.renderBasic;\n\tvar skipHiddenDays = t.skipHiddenDays;\n\tvar getCellsPerWeek = t.getCellsPerWeek;\n\tvar formatDate = calendar.formatDate;\n\t\n\t\n\tfunction render(date, delta) {\n\n\t\tif (delta) {\n\t\t\taddMonths(date, delta);\n\t\t\tdate.setDate(1);\n\t\t}\n\n\t\tvar firstDay = opt('firstDay');\n\n\t\tvar start = cloneDate(date, true);\n\t\tstart.setDate(1);\n\n\t\tvar end = addMonths(cloneDate(start), 1);\n\n\t\tvar visStart = cloneDate(start);\n\t\taddDays(visStart, -((visStart.getDay() - firstDay + 7) % 7));\n\t\tskipHiddenDays(visStart);\n\n\t\tvar visEnd = cloneDate(end);\n\t\taddDays(visEnd, (7 - visEnd.getDay() + firstDay) % 7);\n\t\tskipHiddenDays(visEnd, -1, true);\n\n\t\tvar colCnt = getCellsPerWeek();\n\t\tvar rowCnt = Math.round(dayDiff(visEnd, visStart) / 7); // should be no need for Math.round\n\n\t\tif (opt('weekMode') == 'fixed') {\n\t\t\taddDays(visEnd, (6 - rowCnt) * 7); // add weeks to make up for it\n\t\t\trowCnt = 6;\n\t\t}\n\n\t\tt.title = formatDate(start, opt('titleFormat'));\n\n\t\tt.start = start;\n\t\tt.end = end;\n\t\tt.visStart = visStart;\n\t\tt.visEnd = visEnd;\n\n\t\trenderBasic(rowCnt, colCnt, true);\n\t}\n\t\n\t\n}\n\n;;\n\nfcViews.basicWeek = BasicWeekView;\n\nfunction BasicWeekView(element, calendar) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\t\n\t\n\t// imports\n\tBasicView.call(t, element, calendar, 'basicWeek');\n\tvar opt = t.opt;\n\tvar renderBasic = t.renderBasic;\n\tvar skipHiddenDays = t.skipHiddenDays;\n\tvar getCellsPerWeek = t.getCellsPerWeek;\n\tvar formatDates = calendar.formatDates;\n\t\n\t\n\tfunction render(date, delta) {\n\n\t\tif (delta) {\n\t\t\taddDays(date, delta * 7);\n\t\t}\n\n\t\tvar start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));\n\t\tvar end = addDays(cloneDate(start), 7);\n\n\t\tvar visStart = cloneDate(start);\n\t\tskipHiddenDays(visStart);\n\n\t\tvar visEnd = cloneDate(end);\n\t\tskipHiddenDays(visEnd, -1, true);\n\n\t\tvar colCnt = getCellsPerWeek();\n\n\t\tt.start = start;\n\t\tt.end = end;\n\t\tt.visStart = visStart;\n\t\tt.visEnd = visEnd;\n\n\t\tt.title = formatDates(\n\t\t\tvisStart,\n\t\t\taddDays(cloneDate(visEnd), -1),\n\t\t\topt('titleFormat')\n\t\t);\n\n\t\trenderBasic(1, colCnt, false);\n\t}\n\t\n\t\n}\n\n;;\n\nfcViews.basicDay = BasicDayView;\n\n\nfunction BasicDayView(element, calendar) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\t\n\t\n\t// imports\n\tBasicView.call(t, element, calendar, 'basicDay');\n\tvar opt = t.opt;\n\tvar renderBasic = t.renderBasic;\n\tvar skipHiddenDays = t.skipHiddenDays;\n\tvar formatDate = calendar.formatDate;\n\t\n\t\n\tfunction render(date, delta) {\n\n\t\tif (delta) {\n\t\t\taddDays(date, delta);\n\t\t}\n\t\tskipHiddenDays(date, delta < 0 ? -1 : 1);\n\n\t\tvar start = cloneDate(date, true);\n\t\tvar end = addDays(cloneDate(start), 1);\n\n\t\tt.title = formatDate(date, opt('titleFormat'));\n\n\t\tt.start = t.visStart = start;\n\t\tt.end = t.visEnd = end;\n\n\t\trenderBasic(1, 1, false);\n\t}\n\t\n\t\n}\n\n;;\n\nsetDefaults({\n\tweekMode: 'fixed'\n});\n\n\nfunction BasicView(element, calendar, viewName) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.renderBasic = renderBasic;\n\tt.setHeight = setHeight;\n\tt.setWidth = setWidth;\n\tt.renderDayOverlay = renderDayOverlay;\n\tt.defaultSelectionEnd = defaultSelectionEnd;\n\tt.renderSelection = renderSelection;\n\tt.clearSelection = clearSelection;\n\tt.reportDayClick = reportDayClick; // for selection (kinda hacky)\n\tt.dragStart = dragStart;\n\tt.dragStop = dragStop;\n\tt.defaultEventEnd = defaultEventEnd;\n\tt.getHoverListener = function() { return hoverListener };\n\tt.colLeft = colLeft;\n\tt.colRight = colRight;\n\tt.colContentLeft = colContentLeft;\n\tt.colContentRight = colContentRight;\n\tt.getIsCellAllDay = function() { return true };\n\tt.allDayRow = allDayRow;\n\tt.getRowCnt = function() { return rowCnt };\n\tt.getColCnt = function() { return colCnt };\n\tt.getColWidth = function() { return colWidth };\n\tt.getDaySegmentContainer = function() { return daySegmentContainer };\n\t\n\t\n\t// imports\n\tView.call(t, element, calendar, viewName);\n\tOverlayManager.call(t);\n\tSelectionManager.call(t);\n\tBasicEventRenderer.call(t);\n\tvar opt = t.opt;\n\tvar trigger = t.trigger;\n\tvar renderOverlay = t.renderOverlay;\n\tvar clearOverlays = t.clearOverlays;\n\tvar daySelectionMousedown = t.daySelectionMousedown;\n\tvar cellToDate = t.cellToDate;\n\tvar dateToCell = t.dateToCell;\n\tvar rangeToSegments = t.rangeToSegments;\n\tvar formatDate = calendar.formatDate;\n\t\n\t\n\t// locals\n\t\n\tvar table;\n\tvar head;\n\tvar headCells;\n\tvar body;\n\tvar bodyRows;\n\tvar bodyCells;\n\tvar bodyFirstCells;\n\tvar firstRowCellInners;\n\tvar firstRowCellContentInners;\n\tvar daySegmentContainer;\n\t\n\tvar viewWidth;\n\tvar viewHeight;\n\tvar colWidth;\n\tvar weekNumberWidth;\n\t\n\tvar rowCnt, colCnt;\n\tvar showNumbers;\n\tvar coordinateGrid;\n\tvar hoverListener;\n\tvar colPositions;\n\tvar colContentPositions;\n\t\n\tvar tm;\n\tvar colFormat;\n\tvar showWeekNumbers;\n\tvar weekNumberTitle;\n\tvar weekNumberFormat;\n\t\n\t\n\t\n\t/* Rendering\n\t------------------------------------------------------------*/\n\t\n\t\n\tdisableTextSelection(element.addClass('fc-grid'));\n\t\n\t\n\tfunction renderBasic(_rowCnt, _colCnt, _showNumbers) {\n\t\trowCnt = _rowCnt;\n\t\tcolCnt = _colCnt;\n\t\tshowNumbers = _showNumbers;\n\t\tupdateOptions();\n\n\t\tif (!body) {\n\t\t\tbuildEventContainer();\n\t\t}\n\n\t\tbuildTable();\n\t}\n\t\n\t\n\tfunction updateOptions() {\n\t\ttm = opt('theme') ? 'ui' : 'fc';\n\t\tcolFormat = opt('columnFormat');\n\n\t\t// week # options. (TODO: bad, logic also in other views)\n\t\tshowWeekNumbers = opt('weekNumbers');\n\t\tweekNumberTitle = opt('weekNumberTitle');\n\t\tif (opt('weekNumberCalculation') != 'iso') {\n\t\t\tweekNumberFormat = \"w\";\n\t\t}\n\t\telse {\n\t\t\tweekNumberFormat = \"W\";\n\t\t}\n\t}\n\t\n\t\n\tfunction buildEventContainer() {\n\t\tdaySegmentContainer =\n\t\t\t$(\"<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>\")\n\t\t\t\t.appendTo(element);\n\t}\n\t\n\t\n\tfunction buildTable() {\n\t\tvar html = buildTableHTML();\n\n\t\tif (table) {\n\t\t\ttable.remove();\n\t\t}\n\t\ttable = $(html).appendTo(element);\n\n\t\thead = table.find('thead');\n\t\theadCells = head.find('.fc-day-header');\n\t\tbody = table.find('tbody');\n\t\tbodyRows = body.find('tr');\n\t\tbodyCells = body.find('.fc-day');\n\t\tbodyFirstCells = bodyRows.find('td:first-child');\n\n\t\tfirstRowCellInners = bodyRows.eq(0).find('.fc-day > div');\n\t\tfirstRowCellContentInners = bodyRows.eq(0).find('.fc-day-content > div');\n\t\t\n\t\tmarkFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's\n\t\tmarkFirstLast(bodyRows); // marks first+last td's\n\t\tbodyRows.eq(0).addClass('fc-first');\n\t\tbodyRows.filter(':last').addClass('fc-last');\n\n\t\tbodyCells.each(function(i, _cell) {\n\t\t\tvar date = cellToDate(\n\t\t\t\tMath.floor(i / colCnt),\n\t\t\t\ti % colCnt\n\t\t\t);\n\t\t\ttrigger('dayRender', t, date, $(_cell));\n\t\t});\n\n\t\tdayBind(bodyCells);\n\t}\n\n\n\n\t/* HTML Building\n\t-----------------------------------------------------------*/\n\n\n\tfunction buildTableHTML() {\n\t\tvar html =\n\t\t\t\"<table class='fc-border-separate' style='width:100%' cellspacing='0'>\" +\n\t\t\tbuildHeadHTML() +\n\t\t\tbuildBodyHTML() +\n\t\t\t\"</table>\";\n\n\t\treturn html;\n\t}\n\n\n\tfunction buildHeadHTML() {\n\t\tvar headerClass = tm + \"-widget-header\";\n\t\tvar html = '';\n\t\tvar col;\n\t\tvar date;\n\n\t\thtml += \"<thead><tr>\";\n\n\t\tif (showWeekNumbers) {\n\t\t\thtml +=\n\t\t\t\t\"<th class='fc-week-number \" + headerClass + \"'>\" +\n\t\t\t\thtmlEscape(weekNumberTitle) +\n\t\t\t\t\"</th>\";\n\t\t}\n\n\t\tfor (col=0; col<colCnt; col++) {\n\t\t\tdate = cellToDate(0, col);\n\t\t\thtml +=\n\t\t\t\t\"<th class='fc-day-header fc-\" + dayIDs[date.getDay()] + \" \" + headerClass + \"'>\" +\n\t\t\t\thtmlEscape(formatDate(date, colFormat)) +\n\t\t\t\t\"</th>\";\n\t\t}\n\n\t\thtml += \"</tr></thead>\";\n\n\t\treturn html;\n\t}\n\n\n\tfunction buildBodyHTML() {\n\t\tvar contentClass = tm + \"-widget-content\";\n\t\tvar html = '';\n\t\tvar row;\n\t\tvar col;\n\t\tvar date;\n\n\t\thtml += \"<tbody>\";\n\n\t\tfor (row=0; row<rowCnt; row++) {\n\n\t\t\thtml += \"<tr class='fc-week'>\";\n\n\t\t\tif (showWeekNumbers) {\n\t\t\t\tdate = cellToDate(row, 0);\n\t\t\t\thtml +=\n\t\t\t\t\t\"<td class='fc-week-number \" + contentClass + \"'>\" +\n\t\t\t\t\t\"<div>\" +\n\t\t\t\t\thtmlEscape(formatDate(date, weekNumberFormat)) +\n\t\t\t\t\t\"</div>\" +\n\t\t\t\t\t\"</td>\";\n\t\t\t}\n\n\t\t\tfor (col=0; col<colCnt; col++) {\n\t\t\t\tdate = cellToDate(row, col);\n\t\t\t\thtml += buildCellHTML(date);\n\t\t\t}\n\n\t\t\thtml += \"</tr>\";\n\t\t}\n\n\t\thtml += \"</tbody>\";\n\n\t\treturn html;\n\t}\n\n\n\tfunction buildCellHTML(date) {\n\t\tvar contentClass = tm + \"-widget-content\";\n\t\tvar month = t.start.getMonth();\n\t\tvar today = clearTime(new Date());\n\t\tvar html = '';\n\t\tvar classNames = [\n\t\t\t'fc-day',\n\t\t\t'fc-' + dayIDs[date.getDay()],\n\t\t\tcontentClass\n\t\t];\n\n\t\tif (date.getMonth() != month) {\n\t\t\tclassNames.push('fc-other-month');\n\t\t}\n\t\tif (+date == +today) {\n\t\t\tclassNames.push(\n\t\t\t\t'fc-today',\n\t\t\t\ttm + '-state-highlight'\n\t\t\t);\n\t\t}\n\t\telse if (date < today) {\n\t\t\tclassNames.push('fc-past');\n\t\t}\n\t\telse {\n\t\t\tclassNames.push('fc-future');\n\t\t}\n\n\t\thtml +=\n\t\t\t\"<td\" +\n\t\t\t\" class='\" + classNames.join(' ') + \"'\" +\n\t\t\t\" data-date='\" + formatDate(date, 'yyyy-MM-dd') + \"'\" +\n\t\t\t\">\" +\n\t\t\t\"<div>\";\n\n\t\tif (showNumbers) {\n\t\t\thtml += \"<div class='fc-day-number'>\" + date.getDate() + \"</div>\";\n\t\t}\n\n\t\thtml +=\n\t\t\t\"<div class='fc-day-content'>\" +\n\t\t\t\"<div style='position:relative'>&nbsp;</div>\" +\n\t\t\t\"</div>\" +\n\t\t\t\"</div>\" +\n\t\t\t\"</td>\";\n\n\t\treturn html;\n\t}\n\n\n\n\t/* Dimensions\n\t-----------------------------------------------------------*/\n\t\n\t\n\tfunction setHeight(height) {\n\t\tviewHeight = height;\n\t\t\n\t\tvar bodyHeight = viewHeight - head.height();\n\t\tvar rowHeight;\n\t\tvar rowHeightLast;\n\t\tvar cell;\n\t\t\t\n\t\tif (opt('weekMode') == 'variable') {\n\t\t\trowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6));\n\t\t}else{\n\t\t\trowHeight = Math.floor(bodyHeight / rowCnt);\n\t\t\trowHeightLast = bodyHeight - rowHeight * (rowCnt-1);\n\t\t}\n\t\t\n\t\tbodyFirstCells.each(function(i, _cell) {\n\t\t\tif (i < rowCnt) {\n\t\t\t\tcell = $(_cell);\n\t\t\t\tcell.find('> div').css(\n\t\t\t\t\t'min-height',\n\t\t\t\t\t(i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell)\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\t\n\t}\n\t\n\t\n\tfunction setWidth(width) {\n\t\tviewWidth = width;\n\t\tcolPositions.clear();\n\t\tcolContentPositions.clear();\n\n\t\tweekNumberWidth = 0;\n\t\tif (showWeekNumbers) {\n\t\t\tweekNumberWidth = head.find('th.fc-week-number').outerWidth();\n\t\t}\n\n\t\tcolWidth = Math.floor((viewWidth - weekNumberWidth) / colCnt);\n\t\tsetOuterWidth(headCells.slice(0, -1), colWidth);\n\t}\n\t\n\t\n\t\n\t/* Day clicking and binding\n\t-----------------------------------------------------------*/\n\t\n\t\n\tfunction dayBind(days) {\n\t\tdays.click(dayClick)\n\t\t\t.mousedown(daySelectionMousedown);\n\t}\n\t\n\t\n\tfunction dayClick(ev) {\n\t\tif (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick\n\t\t\tvar date = parseISO8601($(this).data('date'));\n\t\t\ttrigger('dayClick', this, date, true, ev);\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Semi-transparent Overlay Helpers\n\t------------------------------------------------------*/\n\t// TODO: should be consolidated with AgendaView's methods\n\n\n\tfunction renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive\n\n\t\tif (refreshCoordinateGrid) {\n\t\t\tcoordinateGrid.build();\n\t\t}\n\n\t\tvar segments = rangeToSegments(overlayStart, overlayEnd);\n\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tvar segment = segments[i];\n\t\t\tdayBind(\n\t\t\t\trenderCellOverlay(\n\t\t\t\t\tsegment.row,\n\t\t\t\t\tsegment.leftCol,\n\t\t\t\t\tsegment.row,\n\t\t\t\t\tsegment.rightCol\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\t\n\tfunction renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive\n\t\tvar rect = coordinateGrid.rect(row0, col0, row1, col1, element);\n\t\treturn renderOverlay(rect, element);\n\t}\n\t\n\t\n\t\n\t/* Selection\n\t-----------------------------------------------------------------------*/\n\t\n\t\n\tfunction defaultSelectionEnd(startDate, allDay) {\n\t\treturn cloneDate(startDate);\n\t}\n\t\n\t\n\tfunction renderSelection(startDate, endDate, allDay) {\n\t\trenderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???\n\t}\n\t\n\t\n\tfunction clearSelection() {\n\t\tclearOverlays();\n\t}\n\t\n\t\n\tfunction reportDayClick(date, allDay, ev) {\n\t\tvar cell = dateToCell(date);\n\t\tvar _element = bodyCells[cell.row*colCnt + cell.col];\n\t\ttrigger('dayClick', _element, date, allDay, ev);\n\t}\n\t\n\t\n\t\n\t/* External Dragging\n\t-----------------------------------------------------------------------*/\n\t\n\t\n\tfunction dragStart(_dragElement, ev, ui) {\n\t\thoverListener.start(function(cell) {\n\t\t\tclearOverlays();\n\t\t\tif (cell) {\n\t\t\t\trenderCellOverlay(cell.row, cell.col, cell.row, cell.col);\n\t\t\t}\n\t\t}, ev);\n\t}\n\t\n\t\n\tfunction dragStop(_dragElement, ev, ui) {\n\t\tvar cell = hoverListener.stop();\n\t\tclearOverlays();\n\t\tif (cell) {\n\t\t\tvar d = cellToDate(cell);\n\t\t\ttrigger('drop', _dragElement, d, true, ev, ui);\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Utilities\n\t--------------------------------------------------------*/\n\t\n\t\n\tfunction defaultEventEnd(event) {\n\t\treturn cloneDate(event.start);\n\t}\n\t\n\t\n\tcoordinateGrid = new CoordinateGrid(function(rows, cols) {\n\t\tvar e, n, p;\n\t\theadCells.each(function(i, _e) {\n\t\t\te = $(_e);\n\t\t\tn = e.offset().left;\n\t\t\tif (i) {\n\t\t\t\tp[1] = n;\n\t\t\t}\n\t\t\tp = [n];\n\t\t\tcols[i] = p;\n\t\t});\n\t\tp[1] = n + e.outerWidth();\n\t\tbodyRows.each(function(i, _e) {\n\t\t\tif (i < rowCnt) {\n\t\t\t\te = $(_e);\n\t\t\t\tn = e.offset().top;\n\t\t\t\tif (i) {\n\t\t\t\t\tp[1] = n;\n\t\t\t\t}\n\t\t\t\tp = [n];\n\t\t\t\trows[i] = p;\n\t\t\t}\n\t\t});\n\t\tp[1] = n + e.outerHeight();\n\t});\n\t\n\t\n\thoverListener = new HoverListener(coordinateGrid);\n\t\n\tcolPositions = new HorizontalPositionCache(function(col) {\n\t\treturn firstRowCellInners.eq(col);\n\t});\n\n\tcolContentPositions = new HorizontalPositionCache(function(col) {\n\t\treturn firstRowCellContentInners.eq(col);\n\t});\n\n\n\tfunction colLeft(col) {\n\t\treturn colPositions.left(col);\n\t}\n\n\n\tfunction colRight(col) {\n\t\treturn colPositions.right(col);\n\t}\n\t\n\t\n\tfunction colContentLeft(col) {\n\t\treturn colContentPositions.left(col);\n\t}\n\t\n\t\n\tfunction colContentRight(col) {\n\t\treturn colContentPositions.right(col);\n\t}\n\t\n\t\n\tfunction allDayRow(i) {\n\t\treturn bodyRows.eq(i);\n\t}\n\t\n}\n\n;;\n\nfunction BasicEventRenderer() {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.renderEvents = renderEvents;\n\tt.clearEvents = clearEvents;\n\t\n\n\t// imports\n\tDayEventRenderer.call(t);\n\n\t\n\tfunction renderEvents(events, modifiedEventId) {\n\t\tt.renderDayEvents(events, modifiedEventId);\n\t}\n\t\n\t\n\tfunction clearEvents() {\n\t\tt.getDaySegmentContainer().empty();\n\t}\n\n\n\t// TODO: have this class (and AgendaEventRenderer) be responsible for creating the event container div\n\n}\n\n;;\n\nfcViews.agendaWeek = AgendaWeekView;\n\nfunction AgendaWeekView(element, calendar) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\t\n\t\n\t// imports\n\tAgendaView.call(t, element, calendar, 'agendaWeek');\n\tvar opt = t.opt;\n\tvar renderAgenda = t.renderAgenda;\n\tvar skipHiddenDays = t.skipHiddenDays;\n\tvar getCellsPerWeek = t.getCellsPerWeek;\n\tvar formatDates = calendar.formatDates;\n\n\t\n\tfunction render(date, delta) {\n\n\t\tif (delta) {\n\t\t\taddDays(date, delta * 7);\n\t\t}\n\n\t\tvar start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));\n\t\tvar end = addDays(cloneDate(start), 7);\n\n\t\tvar visStart = cloneDate(start);\n\t\tskipHiddenDays(visStart);\n\n\t\tvar visEnd = cloneDate(end);\n\t\tskipHiddenDays(visEnd, -1, true);\n\n\t\tvar colCnt = getCellsPerWeek();\n\n\t\tt.title = formatDates(\n\t\t\tvisStart,\n\t\t\taddDays(cloneDate(visEnd), -1),\n\t\t\topt('titleFormat')\n\t\t);\n\n\t\tt.start = start;\n\t\tt.end = end;\n\t\tt.visStart = visStart;\n\t\tt.visEnd = visEnd;\n\n\t\trenderAgenda(colCnt);\n\t}\n\n}\n\n;;\n\nfcViews.agendaDay = AgendaDayView;\n\n\nfunction AgendaDayView(element, calendar) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.render = render;\n\t\n\t\n\t// imports\n\tAgendaView.call(t, element, calendar, 'agendaDay');\n\tvar opt = t.opt;\n\tvar renderAgenda = t.renderAgenda;\n\tvar skipHiddenDays = t.skipHiddenDays;\n\tvar formatDate = calendar.formatDate;\n\t\n\t\n\tfunction render(date, delta) {\n\n\t\tif (delta) {\n\t\t\taddDays(date, delta);\n\t\t}\n\t\tskipHiddenDays(date, delta < 0 ? -1 : 1);\n\n\t\tvar start = cloneDate(date, true);\n\t\tvar end = addDays(cloneDate(start), 1);\n\n\t\tt.title = formatDate(date, opt('titleFormat'));\n\n\t\tt.start = t.visStart = start;\n\t\tt.end = t.visEnd = end;\n\n\t\trenderAgenda(1);\n\t}\n\t\n\n}\n\n;;\n\nsetDefaults({\n\tallDaySlot: true,\n\tallDayText: 'all-day',\n\tfirstHour: 6,\n\tslotMinutes: 30,\n\tdefaultEventMinutes: 120,\n\taxisFormat: 'h(:mm)tt',\n\ttimeFormat: {\n\t\tagenda: 'h:mm{ - h:mm}'\n\t},\n\tdragOpacity: {\n\t\tagenda: .5\n\t},\n\tminTime: 0,\n\tmaxTime: 24,\n\tslotEventOverlap: true\n});\n\n\n// TODO: make it work in quirks mode (event corners, all-day height)\n// TODO: test liquid width, especially in IE6\n\n\nfunction AgendaView(element, calendar, viewName) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.renderAgenda = renderAgenda;\n\tt.setWidth = setWidth;\n\tt.setHeight = setHeight;\n\tt.afterRender = afterRender;\n\tt.defaultEventEnd = defaultEventEnd;\n\tt.timePosition = timePosition;\n\tt.getIsCellAllDay = getIsCellAllDay;\n\tt.allDayRow = getAllDayRow;\n\tt.getCoordinateGrid = function() { return coordinateGrid }; // specifically for AgendaEventRenderer\n\tt.getHoverListener = function() { return hoverListener };\n\tt.colLeft = colLeft;\n\tt.colRight = colRight;\n\tt.colContentLeft = colContentLeft;\n\tt.colContentRight = colContentRight;\n\tt.getDaySegmentContainer = function() { return daySegmentContainer };\n\tt.getSlotSegmentContainer = function() { return slotSegmentContainer };\n\tt.getMinMinute = function() { return minMinute };\n\tt.getMaxMinute = function() { return maxMinute };\n\tt.getSlotContainer = function() { return slotContainer };\n\tt.getRowCnt = function() { return 1 };\n\tt.getColCnt = function() { return colCnt };\n\tt.getColWidth = function() { return colWidth };\n\tt.getSnapHeight = function() { return snapHeight };\n\tt.getSnapMinutes = function() { return snapMinutes };\n\tt.defaultSelectionEnd = defaultSelectionEnd;\n\tt.renderDayOverlay = renderDayOverlay;\n\tt.renderSelection = renderSelection;\n\tt.clearSelection = clearSelection;\n\tt.reportDayClick = reportDayClick; // selection mousedown hack\n\tt.dragStart = dragStart;\n\tt.dragStop = dragStop;\n\t\n\t\n\t// imports\n\tView.call(t, element, calendar, viewName);\n\tOverlayManager.call(t);\n\tSelectionManager.call(t);\n\tAgendaEventRenderer.call(t);\n\tvar opt = t.opt;\n\tvar trigger = t.trigger;\n\tvar renderOverlay = t.renderOverlay;\n\tvar clearOverlays = t.clearOverlays;\n\tvar reportSelection = t.reportSelection;\n\tvar unselect = t.unselect;\n\tvar daySelectionMousedown = t.daySelectionMousedown;\n\tvar slotSegHtml = t.slotSegHtml;\n\tvar cellToDate = t.cellToDate;\n\tvar dateToCell = t.dateToCell;\n\tvar rangeToSegments = t.rangeToSegments;\n\tvar formatDate = calendar.formatDate;\n\t\n\t\n\t// locals\n\t\n\tvar dayTable;\n\tvar dayHead;\n\tvar dayHeadCells;\n\tvar dayBody;\n\tvar dayBodyCells;\n\tvar dayBodyCellInners;\n\tvar dayBodyCellContentInners;\n\tvar dayBodyFirstCell;\n\tvar dayBodyFirstCellStretcher;\n\tvar slotLayer;\n\tvar daySegmentContainer;\n\tvar allDayTable;\n\tvar allDayRow;\n\tvar slotScroller;\n\tvar slotContainer;\n\tvar slotSegmentContainer;\n\tvar slotTable;\n\tvar selectionHelper;\n\t\n\tvar viewWidth;\n\tvar viewHeight;\n\tvar axisWidth;\n\tvar colWidth;\n\tvar gutterWidth;\n\tvar slotHeight; // TODO: what if slotHeight changes? (see issue 650)\n\n\tvar snapMinutes;\n\tvar snapRatio; // ratio of number of \"selection\" slots to normal slots. (ex: 1, 2, 4)\n\tvar snapHeight; // holds the pixel hight of a \"selection\" slot\n\t\n\tvar colCnt;\n\tvar slotCnt;\n\tvar coordinateGrid;\n\tvar hoverListener;\n\tvar colPositions;\n\tvar colContentPositions;\n\tvar slotTopCache = {};\n\t\n\tvar tm;\n\tvar rtl;\n\tvar minMinute, maxMinute;\n\tvar colFormat;\n\tvar showWeekNumbers;\n\tvar weekNumberTitle;\n\tvar weekNumberFormat;\n\t\n\n\t\n\t/* Rendering\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tdisableTextSelection(element.addClass('fc-agenda'));\n\t\n\t\n\tfunction renderAgenda(c) {\n\t\tcolCnt = c;\n\t\tupdateOptions();\n\n\t\tif (!dayTable) { // first time rendering?\n\t\t\tbuildSkeleton(); // builds day table, slot area, events containers\n\t\t}\n\t\telse {\n\t\t\tbuildDayTable(); // rebuilds day table\n\t\t}\n\t}\n\t\n\t\n\tfunction updateOptions() {\n\n\t\ttm = opt('theme') ? 'ui' : 'fc';\n\t\trtl = opt('isRTL')\n\t\tminMinute = parseTime(opt('minTime'));\n\t\tmaxMinute = parseTime(opt('maxTime'));\n\t\tcolFormat = opt('columnFormat');\n\n\t\t// week # options. (TODO: bad, logic also in other views)\n\t\tshowWeekNumbers = opt('weekNumbers');\n\t\tweekNumberTitle = opt('weekNumberTitle');\n\t\tif (opt('weekNumberCalculation') != 'iso') {\n\t\t\tweekNumberFormat = \"w\";\n\t\t}\n\t\telse {\n\t\t\tweekNumberFormat = \"W\";\n\t\t}\n\n\t\tsnapMinutes = opt('snapMinutes') || opt('slotMinutes');\n\t}\n\n\n\n\t/* Build DOM\n\t-----------------------------------------------------------------------*/\n\n\n\tfunction buildSkeleton() {\n\t\tvar headerClass = tm + \"-widget-header\";\n\t\tvar contentClass = tm + \"-widget-content\";\n\t\tvar s;\n\t\tvar d;\n\t\tvar i;\n\t\tvar maxd;\n\t\tvar minutes;\n\t\tvar slotNormal = opt('slotMinutes') % 15 == 0;\n\t\t\n\t\tbuildDayTable();\n\t\t\n\t\tslotLayer =\n\t\t\t$(\"<div style='position:absolute;z-index:2;left:0;width:100%'/>\")\n\t\t\t\t.appendTo(element);\n\t\t\t\t\n\t\tif (opt('allDaySlot')) {\n\t\t\n\t\t\tdaySegmentContainer =\n\t\t\t\t$(\"<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>\")\n\t\t\t\t\t.appendTo(slotLayer);\n\t\t\n\t\t\ts =\n\t\t\t\t\"<table style='width:100%' class='fc-agenda-allday' cellspacing='0'>\" +\n\t\t\t\t\"<tr>\" +\n\t\t\t\t\"<th class='\" + headerClass + \" fc-agenda-axis'>\" + opt('allDayText') + \"</th>\" +\n\t\t\t\t\"<td>\" +\n\t\t\t\t\"<div class='fc-day-content'><div style='position:relative'/></div>\" +\n\t\t\t\t\"</td>\" +\n\t\t\t\t\"<th class='\" + headerClass + \" fc-agenda-gutter'>&nbsp;</th>\" +\n\t\t\t\t\"</tr>\" +\n\t\t\t\t\"</table>\";\n\t\t\tallDayTable = $(s).appendTo(slotLayer);\n\t\t\tallDayRow = allDayTable.find('tr');\n\t\t\t\n\t\t\tdayBind(allDayRow.find('td'));\n\t\t\t\n\t\t\tslotLayer.append(\n\t\t\t\t\"<div class='fc-agenda-divider \" + headerClass + \"'>\" +\n\t\t\t\t\"<div class='fc-agenda-divider-inner'/>\" +\n\t\t\t\t\"</div>\"\n\t\t\t);\n\t\t\t\n\t\t}else{\n\t\t\n\t\t\tdaySegmentContainer = $([]); // in jQuery 1.4, we can just do $()\n\t\t\n\t\t}\n\t\t\n\t\tslotScroller =\n\t\t\t$(\"<div style='position:absolute;width:100%;overflow-x:hidden;overflow-y:auto'/>\")\n\t\t\t\t.appendTo(slotLayer);\n\t\t\t\t\n\t\tslotContainer =\n\t\t\t$(\"<div style='position:relative;width:100%;overflow:hidden'/>\")\n\t\t\t\t.appendTo(slotScroller);\n\t\t\t\t\n\t\tslotSegmentContainer =\n\t\t\t$(\"<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>\")\n\t\t\t\t.appendTo(slotContainer);\n\t\t\n\t\ts =\n\t\t\t\"<table class='fc-agenda-slots' style='width:100%' cellspacing='0'>\" +\n\t\t\t\"<tbody>\";\n\t\td = zeroDate();\n\t\tmaxd = addMinutes(cloneDate(d), maxMinute);\n\t\taddMinutes(d, minMinute);\n\t\tslotCnt = 0;\n\t\tfor (i=0; d < maxd; i++) {\n\t\t\tminutes = d.getMinutes();\n\t\t\ts +=\n\t\t\t\t\"<tr class='fc-slot\" + i + ' ' + (!minutes ? '' : 'fc-minor') + \"'>\" +\n\t\t\t\t\"<th class='fc-agenda-axis \" + headerClass + \"'>\" +\n\t\t\t\t((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : '&nbsp;') +\n\t\t\t\t\"</th>\" +\n\t\t\t\t\"<td class='\" + contentClass + \"'>\" +\n\t\t\t\t\"<div style='position:relative'>&nbsp;</div>\" +\n\t\t\t\t\"</td>\" +\n\t\t\t\t\"</tr>\";\n\t\t\taddMinutes(d, opt('slotMinutes'));\n\t\t\tslotCnt++;\n\t\t}\n\t\ts +=\n\t\t\t\"</tbody>\" +\n\t\t\t\"</table>\";\n\t\tslotTable = $(s).appendTo(slotContainer);\n\t\t\n\t\tslotBind(slotTable.find('td'));\n\t}\n\n\n\n\t/* Build Day Table\n\t-----------------------------------------------------------------------*/\n\n\n\tfunction buildDayTable() {\n\t\tvar html = buildDayTableHTML();\n\n\t\tif (dayTable) {\n\t\t\tdayTable.remove();\n\t\t}\n\t\tdayTable = $(html).appendTo(element);\n\n\t\tdayHead = dayTable.find('thead');\n\t\tdayHeadCells = dayHead.find('th').slice(1, -1); // exclude gutter\n\t\tdayBody = dayTable.find('tbody');\n\t\tdayBodyCells = dayBody.find('td').slice(0, -1); // exclude gutter\n\t\tdayBodyCellInners = dayBodyCells.find('> div');\n\t\tdayBodyCellContentInners = dayBodyCells.find('.fc-day-content > div');\n\n\t\tdayBodyFirstCell = dayBodyCells.eq(0);\n\t\tdayBodyFirstCellStretcher = dayBodyCellInners.eq(0);\n\t\t\n\t\tmarkFirstLast(dayHead.add(dayHead.find('tr')));\n\t\tmarkFirstLast(dayBody.add(dayBody.find('tr')));\n\n\t\t// TODO: now that we rebuild the cells every time, we should call dayRender\n\t}\n\n\n\tfunction buildDayTableHTML() {\n\t\tvar html =\n\t\t\t\"<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'>\" +\n\t\t\tbuildDayTableHeadHTML() +\n\t\t\tbuildDayTableBodyHTML() +\n\t\t\t\"</table>\";\n\n\t\treturn html;\n\t}\n\n\n\tfunction buildDayTableHeadHTML() {\n\t\tvar headerClass = tm + \"-widget-header\";\n\t\tvar date;\n\t\tvar html = '';\n\t\tvar weekText;\n\t\tvar col;\n\n\t\thtml +=\n\t\t\t\"<thead>\" +\n\t\t\t\"<tr>\";\n\n\t\tif (showWeekNumbers) {\n\t\t\tdate = cellToDate(0, 0);\n\t\t\tweekText = formatDate(date, weekNumberFormat);\n\t\t\tif (rtl) {\n\t\t\t\tweekText += weekNumberTitle;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tweekText = weekNumberTitle + weekText;\n\t\t\t}\n\t\t\thtml +=\n\t\t\t\t\"<th class='fc-agenda-axis fc-week-number \" + headerClass + \"'>\" +\n\t\t\t\thtmlEscape(weekText) +\n\t\t\t\t\"</th>\";\n\t\t}\n\t\telse {\n\t\t\thtml += \"<th class='fc-agenda-axis \" + headerClass + \"'>&nbsp;</th>\";\n\t\t}\n\n\t\tfor (col=0; col<colCnt; col++) {\n\t\t\tdate = cellToDate(0, col);\n\t\t\thtml +=\n\t\t\t\t\"<th class='fc-\" + dayIDs[date.getDay()] + \" fc-col\" + col + ' ' + headerClass + \"'>\" +\n\t\t\t\thtmlEscape(formatDate(date, colFormat)) +\n\t\t\t\t\"</th>\";\n\t\t}\n\n\t\thtml +=\n\t\t\t\"<th class='fc-agenda-gutter \" + headerClass + \"'>&nbsp;</th>\" +\n\t\t\t\"</tr>\" +\n\t\t\t\"</thead>\";\n\n\t\treturn html;\n\t}\n\n\n\tfunction buildDayTableBodyHTML() {\n\t\tvar headerClass = tm + \"-widget-header\"; // TODO: make these when updateOptions() called\n\t\tvar contentClass = tm + \"-widget-content\";\n\t\tvar date;\n\t\tvar today = clearTime(new Date());\n\t\tvar col;\n\t\tvar cellsHTML;\n\t\tvar cellHTML;\n\t\tvar classNames;\n\t\tvar html = '';\n\n\t\thtml +=\n\t\t\t\"<tbody>\" +\n\t\t\t\"<tr>\" +\n\t\t\t\"<th class='fc-agenda-axis \" + headerClass + \"'>&nbsp;</th>\";\n\n\t\tcellsHTML = '';\n\n\t\tfor (col=0; col<colCnt; col++) {\n\n\t\t\tdate = cellToDate(0, col);\n\n\t\t\tclassNames = [\n\t\t\t\t'fc-col' + col,\n\t\t\t\t'fc-' + dayIDs[date.getDay()],\n\t\t\t\tcontentClass\n\t\t\t];\n\t\t\tif (+date == +today) {\n\t\t\t\tclassNames.push(\n\t\t\t\t\ttm + '-state-highlight',\n\t\t\t\t\t'fc-today'\n\t\t\t\t);\n\t\t\t}\n\t\t\telse if (date < today) {\n\t\t\t\tclassNames.push('fc-past');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tclassNames.push('fc-future');\n\t\t\t}\n\n\t\t\tcellHTML =\n\t\t\t\t\"<td class='\" + classNames.join(' ') + \"'>\" +\n\t\t\t\t\"<div>\" +\n\t\t\t\t\"<div class='fc-day-content'>\" +\n\t\t\t\t\"<div style='position:relative'>&nbsp;</div>\" +\n\t\t\t\t\"</div>\" +\n\t\t\t\t\"</div>\" +\n\t\t\t\t\"</td>\";\n\n\t\t\tcellsHTML += cellHTML;\n\t\t}\n\n\t\thtml += cellsHTML;\n\t\thtml +=\n\t\t\t\"<td class='fc-agenda-gutter \" + contentClass + \"'>&nbsp;</td>\" +\n\t\t\t\"</tr>\" +\n\t\t\t\"</tbody>\";\n\n\t\treturn html;\n\t}\n\n\n\t// TODO: data-date on the cells\n\n\t\n\t\n\t/* Dimensions\n\t-----------------------------------------------------------------------*/\n\n\t\n\tfunction setHeight(height) {\n\t\tif (height === undefined) {\n\t\t\theight = viewHeight;\n\t\t}\n\t\tviewHeight = height;\n\t\tslotTopCache = {};\n\t\n\t\tvar headHeight = dayBody.position().top;\n\t\tvar allDayHeight = slotScroller.position().top; // including divider\n\t\tvar bodyHeight = Math.min( // total body height, including borders\n\t\t\theight - headHeight,   // when scrollbars\n\t\t\tslotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border\n\t\t);\n\n\t\tdayBodyFirstCellStretcher\n\t\t\t.height(bodyHeight - vsides(dayBodyFirstCell));\n\t\t\n\t\tslotLayer.css('top', headHeight);\n\t\t\n\t\tslotScroller.height(bodyHeight - allDayHeight - 1);\n\t\t\n\t\t// the stylesheet guarantees that the first row has no border.\n\t\t// this allows .height() to work well cross-browser.\n\t\tslotHeight = slotTable.find('tr:first').height() + 1; // +1 for bottom border\n\n\t\tsnapRatio = opt('slotMinutes') / snapMinutes;\n\t\tsnapHeight = slotHeight / snapRatio;\n\t}\n\t\n\t\n\tfunction setWidth(width) {\n\t\tviewWidth = width;\n\t\tcolPositions.clear();\n\t\tcolContentPositions.clear();\n\n\t\tvar axisFirstCells = dayHead.find('th:first');\n\t\tif (allDayTable) {\n\t\t\taxisFirstCells = axisFirstCells.add(allDayTable.find('th:first'));\n\t\t}\n\t\taxisFirstCells = axisFirstCells.add(slotTable.find('th:first'));\n\t\t\n\t\taxisWidth = 0;\n\t\tsetOuterWidth(\n\t\t\taxisFirstCells\n\t\t\t\t.width('')\n\t\t\t\t.each(function(i, _cell) {\n\t\t\t\t\taxisWidth = Math.max(axisWidth, $(_cell).outerWidth());\n\t\t\t\t}),\n\t\t\taxisWidth\n\t\t);\n\t\t\n\t\tvar gutterCells = dayTable.find('.fc-agenda-gutter');\n\t\tif (allDayTable) {\n\t\t\tgutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter'));\n\t\t}\n\n\t\tvar slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7)\n\t\t\n\t\tgutterWidth = slotScroller.width() - slotTableWidth;\n\t\tif (gutterWidth) {\n\t\t\tsetOuterWidth(gutterCells, gutterWidth);\n\t\t\tgutterCells\n\t\t\t\t.show()\n\t\t\t\t.prev()\n\t\t\t\t.removeClass('fc-last');\n\t\t}else{\n\t\t\tgutterCells\n\t\t\t\t.hide()\n\t\t\t\t.prev()\n\t\t\t\t.addClass('fc-last');\n\t\t}\n\t\t\n\t\tcolWidth = Math.floor((slotTableWidth - axisWidth) / colCnt);\n\t\tsetOuterWidth(dayHeadCells.slice(0, -1), colWidth);\n\t}\n\t\n\n\n\t/* Scrolling\n\t-----------------------------------------------------------------------*/\n\n\n\tfunction resetScroll() {\n\t\tvar d0 = zeroDate();\n\t\tvar scrollDate = cloneDate(d0);\n\t\tscrollDate.setHours(opt('firstHour'));\n\t\tvar top = timePosition(d0, scrollDate) + 1; // +1 for the border\n\t\tfunction scroll() {\n\t\t\tslotScroller.scrollTop(top);\n\t\t}\n\t\tscroll();\n\t\tsetTimeout(scroll, 0); // overrides any previous scroll state made by the browser\n\t}\n\n\n\tfunction afterRender() { // after the view has been freshly rendered and sized\n\t\tresetScroll();\n\t}\n\t\n\t\n\t\n\t/* Slot/Day clicking and binding\n\t-----------------------------------------------------------------------*/\n\t\n\n\tfunction dayBind(cells) {\n\t\tcells.click(slotClick)\n\t\t\t.mousedown(daySelectionMousedown);\n\t}\n\n\n\tfunction slotBind(cells) {\n\t\tcells.click(slotClick)\n\t\t\t.mousedown(slotSelectionMousedown);\n\t}\n\t\n\t\n\tfunction slotClick(ev) {\n\t\tif (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick\n\t\t\tvar col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth));\n\t\t\tvar date = cellToDate(0, col);\n\t\t\tvar rowMatch = this.parentNode.className.match(/fc-slot(\\d+)/); // TODO: maybe use data\n\t\t\tif (rowMatch) {\n\t\t\t\tvar mins = parseInt(rowMatch[1]) * opt('slotMinutes');\n\t\t\t\tvar hours = Math.floor(mins/60);\n\t\t\t\tdate.setHours(hours);\n\t\t\t\tdate.setMinutes(mins%60 + minMinute);\n\t\t\t\ttrigger('dayClick', dayBodyCells[col], date, false, ev);\n\t\t\t}else{\n\t\t\t\ttrigger('dayClick', dayBodyCells[col], date, true, ev);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Semi-transparent Overlay Helpers\n\t-----------------------------------------------------*/\n\t// TODO: should be consolidated with BasicView's methods\n\n\n\tfunction renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive\n\n\t\tif (refreshCoordinateGrid) {\n\t\t\tcoordinateGrid.build();\n\t\t}\n\n\t\tvar segments = rangeToSegments(overlayStart, overlayEnd);\n\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tvar segment = segments[i];\n\t\t\tdayBind(\n\t\t\t\trenderCellOverlay(\n\t\t\t\t\tsegment.row,\n\t\t\t\t\tsegment.leftCol,\n\t\t\t\t\tsegment.row,\n\t\t\t\t\tsegment.rightCol\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\t\n\t\n\tfunction renderCellOverlay(row0, col0, row1, col1) { // only for all-day?\n\t\tvar rect = coordinateGrid.rect(row0, col0, row1, col1, slotLayer);\n\t\treturn renderOverlay(rect, slotLayer);\n\t}\n\t\n\n\tfunction renderSlotOverlay(overlayStart, overlayEnd) {\n\t\tfor (var i=0; i<colCnt; i++) {\n\t\t\tvar dayStart = cellToDate(0, i);\n\t\t\tvar dayEnd = addDays(cloneDate(dayStart), 1);\n\t\t\tvar stretchStart = new Date(Math.max(dayStart, overlayStart));\n\t\t\tvar stretchEnd = new Date(Math.min(dayEnd, overlayEnd));\n\t\t\tif (stretchStart < stretchEnd) {\n\t\t\t\tvar rect = coordinateGrid.rect(0, i, 0, i, slotContainer); // only use it for horizontal coords\n\t\t\t\tvar top = timePosition(dayStart, stretchStart);\n\t\t\t\tvar bottom = timePosition(dayStart, stretchEnd);\n\t\t\t\trect.top = top;\n\t\t\t\trect.height = bottom - top;\n\t\t\t\tslotBind(\n\t\t\t\t\trenderOverlay(rect, slotContainer)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Coordinate Utilities\n\t-----------------------------------------------------------------------------*/\n\t\n\t\n\tcoordinateGrid = new CoordinateGrid(function(rows, cols) {\n\t\tvar e, n, p;\n\t\tdayHeadCells.each(function(i, _e) {\n\t\t\te = $(_e);\n\t\t\tn = e.offset().left;\n\t\t\tif (i) {\n\t\t\t\tp[1] = n;\n\t\t\t}\n\t\t\tp = [n];\n\t\t\tcols[i] = p;\n\t\t});\n\t\tp[1] = n + e.outerWidth();\n\t\tif (opt('allDaySlot')) {\n\t\t\te = allDayRow;\n\t\t\tn = e.offset().top;\n\t\t\trows[0] = [n, n+e.outerHeight()];\n\t\t}\n\t\tvar slotTableTop = slotContainer.offset().top;\n\t\tvar slotScrollerTop = slotScroller.offset().top;\n\t\tvar slotScrollerBottom = slotScrollerTop + slotScroller.outerHeight();\n\t\tfunction constrain(n) {\n\t\t\treturn Math.max(slotScrollerTop, Math.min(slotScrollerBottom, n));\n\t\t}\n\t\tfor (var i=0; i<slotCnt*snapRatio; i++) { // adapt slot count to increased/decreased selection slot count\n\t\t\trows.push([\n\t\t\t\tconstrain(slotTableTop + snapHeight*i),\n\t\t\t\tconstrain(slotTableTop + snapHeight*(i+1))\n\t\t\t]);\n\t\t}\n\t});\n\t\n\t\n\thoverListener = new HoverListener(coordinateGrid);\n\t\n\tcolPositions = new HorizontalPositionCache(function(col) {\n\t\treturn dayBodyCellInners.eq(col);\n\t});\n\t\n\tcolContentPositions = new HorizontalPositionCache(function(col) {\n\t\treturn dayBodyCellContentInners.eq(col);\n\t});\n\t\n\t\n\tfunction colLeft(col) {\n\t\treturn colPositions.left(col);\n\t}\n\n\n\tfunction colContentLeft(col) {\n\t\treturn colContentPositions.left(col);\n\t}\n\n\n\tfunction colRight(col) {\n\t\treturn colPositions.right(col);\n\t}\n\t\n\t\n\tfunction colContentRight(col) {\n\t\treturn colContentPositions.right(col);\n\t}\n\n\n\tfunction getIsCellAllDay(cell) {\n\t\treturn opt('allDaySlot') && !cell.row;\n\t}\n\n\n\tfunction realCellToDate(cell) { // ugh \"real\" ... but blame it on our abuse of the \"cell\" system\n\t\tvar d = cellToDate(0, cell.col);\n\t\tvar slotIndex = cell.row;\n\t\tif (opt('allDaySlot')) {\n\t\t\tslotIndex--;\n\t\t}\n\t\tif (slotIndex >= 0) {\n\t\t\taddMinutes(d, minMinute + slotIndex * snapMinutes);\n\t\t}\n\t\treturn d;\n\t}\n\t\n\t\n\t// get the Y coordinate of the given time on the given day (both Date objects)\n\tfunction timePosition(day, time) { // both date objects. day holds 00:00 of current day\n\t\tday = cloneDate(day, true);\n\t\tif (time < addMinutes(cloneDate(day), minMinute)) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (time >= addMinutes(cloneDate(day), maxMinute)) {\n\t\t\treturn slotTable.height();\n\t\t}\n\t\tvar slotMinutes = opt('slotMinutes'),\n\t\t\tminutes = time.getHours()*60 + time.getMinutes() - minMinute,\n\t\t\tslotI = Math.floor(minutes / slotMinutes),\n\t\t\tslotTop = slotTopCache[slotI];\n\t\tif (slotTop === undefined) {\n\t\t\tslotTop = slotTopCache[slotI] =\n\t\t\t\tslotTable.find('tr').eq(slotI).find('td div')[0].offsetTop;\n\t\t\t\t// .eq() is faster than \":eq()\" selector\n\t\t\t\t// [0].offsetTop is faster than .position().top (do we really need this optimization?)\n\t\t\t\t// a better optimization would be to cache all these divs\n\t\t}\n\t\treturn Math.max(0, Math.round(\n\t\t\tslotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)\n\t\t));\n\t}\n\t\n\t\n\tfunction getAllDayRow(index) {\n\t\treturn allDayRow;\n\t}\n\t\n\t\n\tfunction defaultEventEnd(event) {\n\t\tvar start = cloneDate(event.start);\n\t\tif (event.allDay) {\n\t\t\treturn start;\n\t\t}\n\t\treturn addMinutes(start, opt('defaultEventMinutes'));\n\t}\n\t\n\t\n\t\n\t/* Selection\n\t---------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction defaultSelectionEnd(startDate, allDay) {\n\t\tif (allDay) {\n\t\t\treturn cloneDate(startDate);\n\t\t}\n\t\treturn addMinutes(cloneDate(startDate), opt('slotMinutes'));\n\t}\n\t\n\t\n\tfunction renderSelection(startDate, endDate, allDay) { // only for all-day\n\t\tif (allDay) {\n\t\t\tif (opt('allDaySlot')) {\n\t\t\t\trenderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);\n\t\t\t}\n\t\t}else{\n\t\t\trenderSlotSelection(startDate, endDate);\n\t\t}\n\t}\n\t\n\t\n\tfunction renderSlotSelection(startDate, endDate) {\n\t\tvar helperOption = opt('selectHelper');\n\t\tcoordinateGrid.build();\n\t\tif (helperOption) {\n\t\t\tvar col = dateToCell(startDate).col;\n\t\t\tif (col >= 0 && col < colCnt) { // only works when times are on same day\n\t\t\t\tvar rect = coordinateGrid.rect(0, col, 0, col, slotContainer); // only for horizontal coords\n\t\t\t\tvar top = timePosition(startDate, startDate);\n\t\t\t\tvar bottom = timePosition(startDate, endDate);\n\t\t\t\tif (bottom > top) { // protect against selections that are entirely before or after visible range\n\t\t\t\t\trect.top = top;\n\t\t\t\t\trect.height = bottom - top;\n\t\t\t\t\trect.left += 2;\n\t\t\t\t\trect.width -= 5;\n\t\t\t\t\tif ($.isFunction(helperOption)) {\n\t\t\t\t\t\tvar helperRes = helperOption(startDate, endDate);\n\t\t\t\t\t\tif (helperRes) {\n\t\t\t\t\t\t\trect.position = 'absolute';\n\t\t\t\t\t\t\tselectionHelper = $(helperRes)\n\t\t\t\t\t\t\t\t.css(rect)\n\t\t\t\t\t\t\t\t.appendTo(slotContainer);\n\t\t\t\t\t\t}\n\t\t\t\t\t}else{\n\t\t\t\t\t\trect.isStart = true; // conside rect a \"seg\" now\n\t\t\t\t\t\trect.isEnd = true;   //\n\t\t\t\t\t\tselectionHelper = $(slotSegHtml(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttitle: '',\n\t\t\t\t\t\t\t\tstart: startDate,\n\t\t\t\t\t\t\t\tend: endDate,\n\t\t\t\t\t\t\t\tclassName: ['fc-select-helper'],\n\t\t\t\t\t\t\t\teditable: false\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\trect\n\t\t\t\t\t\t));\n\t\t\t\t\t\tselectionHelper.css('opacity', opt('dragOpacity'));\n\t\t\t\t\t}\n\t\t\t\t\tif (selectionHelper) {\n\t\t\t\t\t\tslotBind(selectionHelper);\n\t\t\t\t\t\tslotContainer.append(selectionHelper);\n\t\t\t\t\t\tsetOuterWidth(selectionHelper, rect.width, true); // needs to be after appended\n\t\t\t\t\t\tsetOuterHeight(selectionHelper, rect.height, true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\trenderSlotOverlay(startDate, endDate);\n\t\t}\n\t}\n\t\n\t\n\tfunction clearSelection() {\n\t\tclearOverlays();\n\t\tif (selectionHelper) {\n\t\t\tselectionHelper.remove();\n\t\t\tselectionHelper = null;\n\t\t}\n\t}\n\t\n\t\n\tfunction slotSelectionMousedown(ev) {\n\t\tif (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button\n\t\t\tunselect(ev);\n\t\t\tvar dates;\n\t\t\thoverListener.start(function(cell, origCell) {\n\t\t\t\tclearSelection();\n\t\t\t\tif (cell && cell.col == origCell.col && !getIsCellAllDay(cell)) {\n\t\t\t\t\tvar d1 = realCellToDate(origCell);\n\t\t\t\t\tvar d2 = realCellToDate(cell);\n\t\t\t\t\tdates = [\n\t\t\t\t\t\td1,\n\t\t\t\t\t\taddMinutes(cloneDate(d1), snapMinutes), // calculate minutes depending on selection slot minutes \n\t\t\t\t\t\td2,\n\t\t\t\t\t\taddMinutes(cloneDate(d2), snapMinutes)\n\t\t\t\t\t].sort(dateCompare);\n\t\t\t\t\trenderSlotSelection(dates[0], dates[3]);\n\t\t\t\t}else{\n\t\t\t\t\tdates = null;\n\t\t\t\t}\n\t\t\t}, ev);\n\t\t\t$(document).one('mouseup', function(ev) {\n\t\t\t\thoverListener.stop();\n\t\t\t\tif (dates) {\n\t\t\t\t\tif (+dates[0] == +dates[1]) {\n\t\t\t\t\t\treportDayClick(dates[0], false, ev);\n\t\t\t\t\t}\n\t\t\t\t\treportSelection(dates[0], dates[3], false, ev);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\tfunction reportDayClick(date, allDay, ev) {\n\t\ttrigger('dayClick', dayBodyCells[dateToCell(date).col], date, allDay, ev);\n\t}\n\t\n\t\n\t\n\t/* External Dragging\n\t--------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction dragStart(_dragElement, ev, ui) {\n\t\thoverListener.start(function(cell) {\n\t\t\tclearOverlays();\n\t\t\tif (cell) {\n\t\t\t\tif (getIsCellAllDay(cell)) {\n\t\t\t\t\trenderCellOverlay(cell.row, cell.col, cell.row, cell.col);\n\t\t\t\t}else{\n\t\t\t\t\tvar d1 = realCellToDate(cell);\n\t\t\t\t\tvar d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));\n\t\t\t\t\trenderSlotOverlay(d1, d2);\n\t\t\t\t}\n\t\t\t}\n\t\t}, ev);\n\t}\n\t\n\t\n\tfunction dragStop(_dragElement, ev, ui) {\n\t\tvar cell = hoverListener.stop();\n\t\tclearOverlays();\n\t\tif (cell) {\n\t\t\ttrigger('drop', _dragElement, realCellToDate(cell), getIsCellAllDay(cell), ev, ui);\n\t\t}\n\t}\n\t\n\n}\n\n;;\n\nfunction AgendaEventRenderer() {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.renderEvents = renderEvents;\n\tt.clearEvents = clearEvents;\n\tt.slotSegHtml = slotSegHtml;\n\t\n\t\n\t// imports\n\tDayEventRenderer.call(t);\n\tvar opt = t.opt;\n\tvar trigger = t.trigger;\n\tvar isEventDraggable = t.isEventDraggable;\n\tvar isEventResizable = t.isEventResizable;\n\tvar eventEnd = t.eventEnd;\n\tvar eventElementHandlers = t.eventElementHandlers;\n\tvar setHeight = t.setHeight;\n\tvar getDaySegmentContainer = t.getDaySegmentContainer;\n\tvar getSlotSegmentContainer = t.getSlotSegmentContainer;\n\tvar getHoverListener = t.getHoverListener;\n\tvar getMaxMinute = t.getMaxMinute;\n\tvar getMinMinute = t.getMinMinute;\n\tvar timePosition = t.timePosition;\n\tvar getIsCellAllDay = t.getIsCellAllDay;\n\tvar colContentLeft = t.colContentLeft;\n\tvar colContentRight = t.colContentRight;\n\tvar cellToDate = t.cellToDate;\n\tvar getColCnt = t.getColCnt;\n\tvar getColWidth = t.getColWidth;\n\tvar getSnapHeight = t.getSnapHeight;\n\tvar getSnapMinutes = t.getSnapMinutes;\n\tvar getSlotContainer = t.getSlotContainer;\n\tvar reportEventElement = t.reportEventElement;\n\tvar showEvents = t.showEvents;\n\tvar hideEvents = t.hideEvents;\n\tvar eventDrop = t.eventDrop;\n\tvar eventResize = t.eventResize;\n\tvar renderDayOverlay = t.renderDayOverlay;\n\tvar clearOverlays = t.clearOverlays;\n\tvar renderDayEvents = t.renderDayEvents;\n\tvar calendar = t.calendar;\n\tvar formatDate = calendar.formatDate;\n\tvar formatDates = calendar.formatDates;\n\n\n\t// overrides\n\tt.draggableDayEvent = draggableDayEvent;\n\n\t\n\t\n\t/* Rendering\n\t----------------------------------------------------------------------------*/\n\t\n\n\tfunction renderEvents(events, modifiedEventId) {\n\t\tvar i, len=events.length,\n\t\t\tdayEvents=[],\n\t\t\tslotEvents=[];\n\t\tfor (i=0; i<len; i++) {\n\t\t\tif (events[i].allDay) {\n\t\t\t\tdayEvents.push(events[i]);\n\t\t\t}else{\n\t\t\t\tslotEvents.push(events[i]);\n\t\t\t}\n\t\t}\n\n\t\tif (opt('allDaySlot')) {\n\t\t\trenderDayEvents(dayEvents, modifiedEventId);\n\t\t\tsetHeight(); // no params means set to viewHeight\n\t\t}\n\n\t\trenderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);\n\t}\n\t\n\t\n\tfunction clearEvents() {\n\t\tgetDaySegmentContainer().empty();\n\t\tgetSlotSegmentContainer().empty();\n\t}\n\n\t\n\tfunction compileSlotSegs(events) {\n\t\tvar colCnt = getColCnt(),\n\t\t\tminMinute = getMinMinute(),\n\t\t\tmaxMinute = getMaxMinute(),\n\t\t\td,\n\t\t\tvisEventEnds = $.map(events, slotEventEnd),\n\t\t\ti,\n\t\t\tj, seg,\n\t\t\tcolSegs,\n\t\t\tsegs = [];\n\n\t\tfor (i=0; i<colCnt; i++) {\n\n\t\t\td = cellToDate(0, i);\n\t\t\taddMinutes(d, minMinute);\n\n\t\t\tcolSegs = sliceSegs(\n\t\t\t\tevents,\n\t\t\t\tvisEventEnds,\n\t\t\t\td,\n\t\t\t\taddMinutes(cloneDate(d), maxMinute-minMinute)\n\t\t\t);\n\n\t\t\tcolSegs = placeSlotSegs(colSegs); // returns a new order\n\n\t\t\tfor (j=0; j<colSegs.length; j++) {\n\t\t\t\tseg = colSegs[j];\n\t\t\t\tseg.col = i;\n\t\t\t\tsegs.push(seg);\n\t\t\t}\n\t\t}\n\n\t\treturn segs;\n\t}\n\n\n\tfunction sliceSegs(events, visEventEnds, start, end) {\n\t\tvar segs = [],\n\t\t\ti, len=events.length, event,\n\t\t\teventStart, eventEnd,\n\t\t\tsegStart, segEnd,\n\t\t\tisStart, isEnd;\n\t\tfor (i=0; i<len; i++) {\n\t\t\tevent = events[i];\n\t\t\teventStart = event.start;\n\t\t\teventEnd = visEventEnds[i];\n\t\t\tif (eventEnd > start && eventStart < end) {\n\t\t\t\tif (eventStart < start) {\n\t\t\t\t\tsegStart = cloneDate(start);\n\t\t\t\t\tisStart = false;\n\t\t\t\t}else{\n\t\t\t\t\tsegStart = eventStart;\n\t\t\t\t\tisStart = true;\n\t\t\t\t}\n\t\t\t\tif (eventEnd > end) {\n\t\t\t\t\tsegEnd = cloneDate(end);\n\t\t\t\t\tisEnd = false;\n\t\t\t\t}else{\n\t\t\t\t\tsegEnd = eventEnd;\n\t\t\t\t\tisEnd = true;\n\t\t\t\t}\n\t\t\t\tsegs.push({\n\t\t\t\t\tevent: event,\n\t\t\t\t\tstart: segStart,\n\t\t\t\t\tend: segEnd,\n\t\t\t\t\tisStart: isStart,\n\t\t\t\t\tisEnd: isEnd\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn segs.sort(compareSlotSegs);\n\t}\n\n\n\tfunction slotEventEnd(event) {\n\t\tif (event.end) {\n\t\t\treturn cloneDate(event.end);\n\t\t}else{\n\t\t\treturn addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));\n\t\t}\n\t}\n\t\n\t\n\t// renders events in the 'time slots' at the bottom\n\t// TODO: when we refactor this, when user returns `false` eventRender, don't have empty space\n\t// TODO: refactor will include using pixels to detect collisions instead of dates (handy for seg cmp)\n\t\n\tfunction renderSlotSegs(segs, modifiedEventId) {\n\t\n\t\tvar i, segCnt=segs.length, seg,\n\t\t\tevent,\n\t\t\ttop,\n\t\t\tbottom,\n\t\t\tcolumnLeft,\n\t\t\tcolumnRight,\n\t\t\tcolumnWidth,\n\t\t\twidth,\n\t\t\tleft,\n\t\t\tright,\n\t\t\thtml = '',\n\t\t\teventElements,\n\t\t\teventElement,\n\t\t\ttriggerRes,\n\t\t\ttitleElement,\n\t\t\theight,\n\t\t\tslotSegmentContainer = getSlotSegmentContainer(),\n\t\t\tisRTL = opt('isRTL');\n\t\t\t\n\t\t// calculate position/dimensions, create html\n\t\tfor (i=0; i<segCnt; i++) {\n\t\t\tseg = segs[i];\n\t\t\tevent = seg.event;\n\t\t\ttop = timePosition(seg.start, seg.start);\n\t\t\tbottom = timePosition(seg.start, seg.end);\n\t\t\tcolumnLeft = colContentLeft(seg.col);\n\t\t\tcolumnRight = colContentRight(seg.col);\n\t\t\tcolumnWidth = columnRight - columnLeft;\n\n\t\t\t// shave off space on right near scrollbars (2.5%)\n\t\t\t// TODO: move this to CSS somehow\n\t\t\tcolumnRight -= columnWidth * .025;\n\t\t\tcolumnWidth = columnRight - columnLeft;\n\n\t\t\twidth = columnWidth * (seg.forwardCoord - seg.backwardCoord);\n\n\t\t\tif (opt('slotEventOverlap')) {\n\t\t\t\t// double the width while making sure resize handle is visible\n\t\t\t\t// (assumed to be 20px wide)\n\t\t\t\twidth = Math.max(\n\t\t\t\t\t(width - (20/2)) * 2,\n\t\t\t\t\twidth // narrow columns will want to make the segment smaller than\n\t\t\t\t\t\t// the natural width. don't allow it\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (isRTL) {\n\t\t\t\tright = columnRight - seg.backwardCoord * columnWidth;\n\t\t\t\tleft = right - width;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tleft = columnLeft + seg.backwardCoord * columnWidth;\n\t\t\t\tright = left + width;\n\t\t\t}\n\n\t\t\t// make sure horizontal coordinates are in bounds\n\t\t\tleft = Math.max(left, columnLeft);\n\t\t\tright = Math.min(right, columnRight);\n\t\t\twidth = right - left;\n\n\t\t\tseg.top = top;\n\t\t\tseg.left = left;\n\t\t\tseg.outerWidth = width;\n\t\t\tseg.outerHeight = bottom - top;\n\t\t\thtml += slotSegHtml(event, seg);\n\t\t}\n\n\t\tslotSegmentContainer[0].innerHTML = html; // faster than html()\n\t\teventElements = slotSegmentContainer.children();\n\t\t\n\t\t// retrieve elements, run through eventRender callback, bind event handlers\n\t\tfor (i=0; i<segCnt; i++) {\n\t\t\tseg = segs[i];\n\t\t\tevent = seg.event;\n\t\t\teventElement = $(eventElements[i]); // faster than eq()\n\t\t\ttriggerRes = trigger('eventRender', event, event, eventElement);\n\t\t\tif (triggerRes === false) {\n\t\t\t\teventElement.remove();\n\t\t\t}else{\n\t\t\t\tif (triggerRes && triggerRes !== true) {\n\t\t\t\t\teventElement.remove();\n\t\t\t\t\teventElement = $(triggerRes)\n\t\t\t\t\t\t.css({\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: seg.top,\n\t\t\t\t\t\t\tleft: seg.left\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.appendTo(slotSegmentContainer);\n\t\t\t\t}\n\t\t\t\tseg.element = eventElement;\n\t\t\t\tif (event._id === modifiedEventId) {\n\t\t\t\t\tbindSlotSeg(event, eventElement, seg);\n\t\t\t\t}else{\n\t\t\t\t\teventElement[0]._fci = i; // for lazySegBind\n\t\t\t\t}\n\t\t\t\treportEventElement(event, eventElement);\n\t\t\t}\n\t\t}\n\t\t\n\t\tlazySegBind(slotSegmentContainer, segs, bindSlotSeg);\n\t\t\n\t\t// record event sides and title positions\n\t\tfor (i=0; i<segCnt; i++) {\n\t\t\tseg = segs[i];\n\t\t\tif (eventElement = seg.element) {\n\t\t\t\tseg.vsides = vsides(eventElement, true);\n\t\t\t\tseg.hsides = hsides(eventElement, true);\n\t\t\t\ttitleElement = eventElement.find('.fc-event-title');\n\t\t\t\tif (titleElement.length) {\n\t\t\t\t\tseg.contentTop = titleElement[0].offsetTop;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// set all positions/dimensions at once\n\t\tfor (i=0; i<segCnt; i++) {\n\t\t\tseg = segs[i];\n\t\t\tif (eventElement = seg.element) {\n\t\t\t\teventElement[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';\n\t\t\t\theight = Math.max(0, seg.outerHeight - seg.vsides);\n\t\t\t\teventElement[0].style.height = height + 'px';\n\t\t\t\tevent = seg.event;\n\t\t\t\tif (seg.contentTop !== undefined && height - seg.contentTop < 10) {\n\t\t\t\t\t// not enough room for title, put it in the time (TODO: maybe make both display:inline instead)\n\t\t\t\t\teventElement.find('div.fc-event-time')\n\t\t\t\t\t\t.text(formatDate(event.start, opt('timeFormat')) + ' - ' + event.title);\n\t\t\t\t\teventElement.find('div.fc-event-title')\n\t\t\t\t\t\t.remove();\n\t\t\t\t}\n\t\t\t\ttrigger('eventAfterRender', event, event, eventElement);\n\t\t\t}\n\t\t}\n\t\t\t\t\t\n\t}\n\t\n\t\n\tfunction slotSegHtml(event, seg) {\n\t\tvar html = \"<\";\n\t\tvar url = event.url;\n\t\tvar skinCss = getSkinCss(event, opt);\n\t\tvar classes = ['fc-event', 'fc-event-vert'];\n\t\tif (isEventDraggable(event)) {\n\t\t\tclasses.push('fc-event-draggable');\n\t\t}\n\t\tif (seg.isStart) {\n\t\t\tclasses.push('fc-event-start');\n\t\t}\n\t\tif (seg.isEnd) {\n\t\t\tclasses.push('fc-event-end');\n\t\t}\n\t\tclasses = classes.concat(event.className);\n\t\tif (event.source) {\n\t\t\tclasses = classes.concat(event.source.className || []);\n\t\t}\n\t\tif (url) {\n\t\t\thtml += \"a href='\" + htmlEscape(event.url) + \"'\";\n\t\t}else{\n\t\t\thtml += \"div\";\n\t\t}\n\t\thtml +=\n\t\t\t\" class='\" + classes.join(' ') + \"'\" +\n\t\t\t\" style=\" +\n\t\t\t\t\"'\" +\n\t\t\t\t\"position:absolute;\" +\n\t\t\t\t\"top:\" + seg.top + \"px;\" +\n\t\t\t\t\"left:\" + seg.left + \"px;\" +\n\t\t\t\tskinCss +\n\t\t\t\t\"'\" +\n\t\t\t\">\" +\n\t\t\t\"<div class='fc-event-inner'>\" +\n\t\t\t\"<div class='fc-event-time'>\" +\n\t\t\thtmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +\n\t\t\t\"</div>\" +\n\t\t\t\"<div class='fc-event-title'>\" +\n\t\t\thtmlEscape(event.title || '') +\n\t\t\t\"</div>\" +\n\t\t\t\"</div>\" +\n\t\t\t\"<div class='fc-event-bg'></div>\";\n\t\tif (seg.isEnd && isEventResizable(event)) {\n\t\t\thtml +=\n\t\t\t\t\"<div class='ui-resizable-handle ui-resizable-s'>=</div>\";\n\t\t}\n\t\thtml +=\n\t\t\t\"</\" + (url ? \"a\" : \"div\") + \">\";\n\t\treturn html;\n\t}\n\t\n\t\n\tfunction bindSlotSeg(event, eventElement, seg) {\n\t\tvar timeElement = eventElement.find('div.fc-event-time');\n\t\tif (isEventDraggable(event)) {\n\t\t\tdraggableSlotEvent(event, eventElement, timeElement);\n\t\t}\n\t\tif (seg.isEnd && isEventResizable(event)) {\n\t\t\tresizableSlotEvent(event, eventElement, timeElement);\n\t\t}\n\t\teventElementHandlers(event, eventElement);\n\t}\n\t\n\t\n\t\n\t/* Dragging\n\t-----------------------------------------------------------------------------------*/\n\t\n\t\n\t// when event starts out FULL-DAY\n\t// overrides DayEventRenderer's version because it needs to account for dragging elements\n\t// to and from the slot area.\n\t\n\tfunction draggableDayEvent(event, eventElement, seg) {\n\t\tvar isStart = seg.isStart;\n\t\tvar origWidth;\n\t\tvar revert;\n\t\tvar allDay = true;\n\t\tvar dayDelta;\n\t\tvar hoverListener = getHoverListener();\n\t\tvar colWidth = getColWidth();\n\t\tvar snapHeight = getSnapHeight();\n\t\tvar snapMinutes = getSnapMinutes();\n\t\tvar minMinute = getMinMinute();\n\t\teventElement.draggable({\n\t\t\topacity: opt('dragOpacity', 'month'), // use whatever the month view was using\n\t\t\trevertDuration: opt('dragRevertDuration'),\n\t\t\tstart: function(ev, ui) {\n\t\t\t\ttrigger('eventDragStart', eventElement, event, ev, ui);\n\t\t\t\thideEvents(event, eventElement);\n\t\t\t\torigWidth = eventElement.width();\n\t\t\t\thoverListener.start(function(cell, origCell) {\n\t\t\t\t\tclearOverlays();\n\t\t\t\t\tif (cell) {\n\t\t\t\t\t\trevert = false;\n\t\t\t\t\t\tvar origDate = cellToDate(0, origCell.col);\n\t\t\t\t\t\tvar date = cellToDate(0, cell.col);\n\t\t\t\t\t\tdayDelta = dayDiff(date, origDate);\n\t\t\t\t\t\tif (!cell.row) {\n\t\t\t\t\t\t\t// on full-days\n\t\t\t\t\t\t\trenderDayOverlay(\n\t\t\t\t\t\t\t\taddDays(cloneDate(event.start), dayDelta),\n\t\t\t\t\t\t\t\taddDays(exclEndDay(event), dayDelta)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tresetElement();\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t// mouse is over bottom slots\n\t\t\t\t\t\t\tif (isStart) {\n\t\t\t\t\t\t\t\tif (allDay) {\n\t\t\t\t\t\t\t\t\t// convert event to temporary slot-event\n\t\t\t\t\t\t\t\t\teventElement.width(colWidth - 10); // don't use entire width\n\t\t\t\t\t\t\t\t\tsetOuterHeight(\n\t\t\t\t\t\t\t\t\t\teventElement,\n\t\t\t\t\t\t\t\t\t\tsnapHeight * Math.round(\n\t\t\t\t\t\t\t\t\t\t\t(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) /\n\t\t\t\t\t\t\t\t\t\t\t\tsnapMinutes\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\teventElement.draggable('option', 'grid', [colWidth, 1]);\n\t\t\t\t\t\t\t\t\tallDay = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\trevert = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\trevert = revert || (allDay && !dayDelta);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tresetElement();\n\t\t\t\t\t\trevert = true;\n\t\t\t\t\t}\n\t\t\t\t\teventElement.draggable('option', 'revert', revert);\n\t\t\t\t}, ev, 'drag');\n\t\t\t},\n\t\t\tstop: function(ev, ui) {\n\t\t\t\thoverListener.stop();\n\t\t\t\tclearOverlays();\n\t\t\t\ttrigger('eventDragStop', eventElement, event, ev, ui);\n\t\t\t\tif (revert) {\n\t\t\t\t\t// hasn't moved or is out of bounds (draggable has already reverted)\n\t\t\t\t\tresetElement();\n\t\t\t\t\teventElement.css('filter', ''); // clear IE opacity side-effects\n\t\t\t\t\tshowEvents(event, eventElement);\n\t\t\t\t}else{\n\t\t\t\t\t// changed!\n\t\t\t\t\tvar minuteDelta = 0;\n\t\t\t\t\tif (!allDay) {\n\t\t\t\t\t\tminuteDelta = Math.round((eventElement.offset().top - getSlotContainer().offset().top) / snapHeight)\n\t\t\t\t\t\t\t* snapMinutes\n\t\t\t\t\t\t\t+ minMinute\n\t\t\t\t\t\t\t- (event.start.getHours() * 60 + event.start.getMinutes());\n\t\t\t\t\t}\n\t\t\t\t\teventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tfunction resetElement() {\n\t\t\tif (!allDay) {\n\t\t\t\teventElement\n\t\t\t\t\t.width(origWidth)\n\t\t\t\t\t.height('')\n\t\t\t\t\t.draggable('option', 'grid', null);\n\t\t\t\tallDay = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t// when event starts out IN TIMESLOTS\n\t\n\tfunction draggableSlotEvent(event, eventElement, timeElement) {\n\t\tvar coordinateGrid = t.getCoordinateGrid();\n\t\tvar colCnt = getColCnt();\n\t\tvar colWidth = getColWidth();\n\t\tvar snapHeight = getSnapHeight();\n\t\tvar snapMinutes = getSnapMinutes();\n\n\t\t// states\n\t\tvar origPosition; // original position of the element, not the mouse\n\t\tvar origCell;\n\t\tvar isInBounds, prevIsInBounds;\n\t\tvar isAllDay, prevIsAllDay;\n\t\tvar colDelta, prevColDelta;\n\t\tvar dayDelta; // derived from colDelta\n\t\tvar minuteDelta, prevMinuteDelta;\n\n\t\teventElement.draggable({\n\t\t\tscroll: false,\n\t\t\tgrid: [ colWidth, snapHeight ],\n\t\t\taxis: colCnt==1 ? 'y' : false,\n\t\t\topacity: opt('dragOpacity'),\n\t\t\trevertDuration: opt('dragRevertDuration'),\n\t\t\tstart: function(ev, ui) {\n\n\t\t\t\ttrigger('eventDragStart', eventElement, event, ev, ui);\n\t\t\t\thideEvents(event, eventElement);\n\n\t\t\t\tcoordinateGrid.build();\n\n\t\t\t\t// initialize states\n\t\t\t\torigPosition = eventElement.position();\n\t\t\t\torigCell = coordinateGrid.cell(ev.pageX, ev.pageY);\n\t\t\t\tisInBounds = prevIsInBounds = true;\n\t\t\t\tisAllDay = prevIsAllDay = getIsCellAllDay(origCell);\n\t\t\t\tcolDelta = prevColDelta = 0;\n\t\t\t\tdayDelta = 0;\n\t\t\t\tminuteDelta = prevMinuteDelta = 0;\n\n\t\t\t},\n\t\t\tdrag: function(ev, ui) {\n\n\t\t\t\t// NOTE: this `cell` value is only useful for determining in-bounds and all-day.\n\t\t\t\t// Bad for anything else due to the discrepancy between the mouse position and the\n\t\t\t\t// element position while snapping. (problem revealed in PR #55)\n\t\t\t\t//\n\t\t\t\t// PS- the problem exists for draggableDayEvent() when dragging an all-day event to a slot event.\n\t\t\t\t// We should overhaul the dragging system and stop relying on jQuery UI.\n\t\t\t\tvar cell = coordinateGrid.cell(ev.pageX, ev.pageY);\n\n\t\t\t\t// update states\n\t\t\t\tisInBounds = !!cell;\n\t\t\t\tif (isInBounds) {\n\t\t\t\t\tisAllDay = getIsCellAllDay(cell);\n\n\t\t\t\t\t// calculate column delta\n\t\t\t\t\tcolDelta = Math.round((ui.position.left - origPosition.left) / colWidth);\n\t\t\t\t\tif (colDelta != prevColDelta) {\n\t\t\t\t\t\t// calculate the day delta based off of the original clicked column and the column delta\n\t\t\t\t\t\tvar origDate = cellToDate(0, origCell.col);\n\t\t\t\t\t\tvar col = origCell.col + colDelta;\n\t\t\t\t\t\tcol = Math.max(0, col);\n\t\t\t\t\t\tcol = Math.min(colCnt-1, col);\n\t\t\t\t\t\tvar date = cellToDate(0, col);\n\t\t\t\t\t\tdayDelta = dayDiff(date, origDate);\n\t\t\t\t\t}\n\n\t\t\t\t\t// calculate minute delta (only if over slots)\n\t\t\t\t\tif (!isAllDay) {\n\t\t\t\t\t\tminuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// any state changes?\n\t\t\t\tif (\n\t\t\t\t\tisInBounds != prevIsInBounds ||\n\t\t\t\t\tisAllDay != prevIsAllDay ||\n\t\t\t\t\tcolDelta != prevColDelta ||\n\t\t\t\t\tminuteDelta != prevMinuteDelta\n\t\t\t\t) {\n\n\t\t\t\t\tupdateUI();\n\n\t\t\t\t\t// update previous states for next time\n\t\t\t\t\tprevIsInBounds = isInBounds;\n\t\t\t\t\tprevIsAllDay = isAllDay;\n\t\t\t\t\tprevColDelta = colDelta;\n\t\t\t\t\tprevMinuteDelta = minuteDelta;\n\t\t\t\t}\n\n\t\t\t\t// if out-of-bounds, revert when done, and vice versa.\n\t\t\t\teventElement.draggable('option', 'revert', !isInBounds);\n\n\t\t\t},\n\t\t\tstop: function(ev, ui) {\n\n\t\t\t\tclearOverlays();\n\t\t\t\ttrigger('eventDragStop', eventElement, event, ev, ui);\n\n\t\t\t\tif (isInBounds && (isAllDay || dayDelta || minuteDelta)) { // changed!\n\t\t\t\t\teventDrop(this, event, dayDelta, isAllDay ? 0 : minuteDelta, isAllDay, ev, ui);\n\t\t\t\t}\n\t\t\t\telse { // either no change or out-of-bounds (draggable has already reverted)\n\n\t\t\t\t\t// reset states for next time, and for updateUI()\n\t\t\t\t\tisInBounds = true;\n\t\t\t\t\tisAllDay = false;\n\t\t\t\t\tcolDelta = 0;\n\t\t\t\t\tdayDelta = 0;\n\t\t\t\t\tminuteDelta = 0;\n\n\t\t\t\t\tupdateUI();\n\t\t\t\t\teventElement.css('filter', ''); // clear IE opacity side-effects\n\n\t\t\t\t\t// sometimes fast drags make event revert to wrong position, so reset.\n\t\t\t\t\t// also, if we dragged the element out of the area because of snapping,\n\t\t\t\t\t// but the *mouse* is still in bounds, we need to reset the position.\n\t\t\t\t\teventElement.css(origPosition);\n\n\t\t\t\t\tshowEvents(event, eventElement);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tfunction updateUI() {\n\t\t\tclearOverlays();\n\t\t\tif (isInBounds) {\n\t\t\t\tif (isAllDay) {\n\t\t\t\t\ttimeElement.hide();\n\t\t\t\t\teventElement.draggable('option', 'grid', null); // disable grid snapping\n\t\t\t\t\trenderDayOverlay(\n\t\t\t\t\t\taddDays(cloneDate(event.start), dayDelta),\n\t\t\t\t\t\taddDays(exclEndDay(event), dayDelta)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tupdateTimeText(minuteDelta);\n\t\t\t\t\ttimeElement.css('display', ''); // show() was causing display=inline\n\t\t\t\t\teventElement.draggable('option', 'grid', [colWidth, snapHeight]); // re-enable grid snapping\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction updateTimeText(minuteDelta) {\n\t\t\tvar newStart = addMinutes(cloneDate(event.start), minuteDelta);\n\t\t\tvar newEnd;\n\t\t\tif (event.end) {\n\t\t\t\tnewEnd = addMinutes(cloneDate(event.end), minuteDelta);\n\t\t\t}\n\t\t\ttimeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));\n\t\t}\n\n\t}\n\t\n\t\n\t\n\t/* Resizing\n\t--------------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction resizableSlotEvent(event, eventElement, timeElement) {\n\t\tvar snapDelta, prevSnapDelta;\n\t\tvar snapHeight = getSnapHeight();\n\t\tvar snapMinutes = getSnapMinutes();\n\t\teventElement.resizable({\n\t\t\thandles: {\n\t\t\t\ts: '.ui-resizable-handle'\n\t\t\t},\n\t\t\tgrid: snapHeight,\n\t\t\tstart: function(ev, ui) {\n\t\t\t\tsnapDelta = prevSnapDelta = 0;\n\t\t\t\thideEvents(event, eventElement);\n\t\t\t\ttrigger('eventResizeStart', this, event, ev, ui);\n\t\t\t},\n\t\t\tresize: function(ev, ui) {\n\t\t\t\t// don't rely on ui.size.height, doesn't take grid into account\n\t\t\t\tsnapDelta = Math.round((Math.max(snapHeight, eventElement.height()) - ui.originalSize.height) / snapHeight);\n\t\t\t\tif (snapDelta != prevSnapDelta) {\n\t\t\t\t\ttimeElement.text(\n\t\t\t\t\t\tformatDates(\n\t\t\t\t\t\t\tevent.start,\n\t\t\t\t\t\t\t(!snapDelta && !event.end) ? null : // no change, so don't display time range\n\t\t\t\t\t\t\t\taddMinutes(eventEnd(event), snapMinutes*snapDelta),\n\t\t\t\t\t\t\topt('timeFormat')\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t\tprevSnapDelta = snapDelta;\n\t\t\t\t}\n\t\t\t},\n\t\t\tstop: function(ev, ui) {\n\t\t\t\ttrigger('eventResizeStop', this, event, ev, ui);\n\t\t\t\tif (snapDelta) {\n\t\t\t\t\teventResize(this, event, 0, snapMinutes*snapDelta, ev, ui);\n\t\t\t\t}else{\n\t\t\t\t\tshowEvents(event, eventElement);\n\t\t\t\t\t// BUG: if event was really short, need to put title back in span\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\t\n\n}\n\n\n\n/* Agenda Event Segment Utilities\n-----------------------------------------------------------------------------*/\n\n\n// Sets the seg.backwardCoord and seg.forwardCoord on each segment and returns a new\n// list in the order they should be placed into the DOM (an implicit z-index).\nfunction placeSlotSegs(segs) {\n\tvar levels = buildSlotSegLevels(segs);\n\tvar level0 = levels[0];\n\tvar i;\n\n\tcomputeForwardSlotSegs(levels);\n\n\tif (level0) {\n\n\t\tfor (i=0; i<level0.length; i++) {\n\t\t\tcomputeSlotSegPressures(level0[i]);\n\t\t}\n\n\t\tfor (i=0; i<level0.length; i++) {\n\t\t\tcomputeSlotSegCoords(level0[i], 0, 0);\n\t\t}\n\t}\n\n\treturn flattenSlotSegLevels(levels);\n}\n\n\n// Builds an array of segments \"levels\". The first level will be the leftmost tier of segments\n// if the calendar is left-to-right, or the rightmost if the calendar is right-to-left.\nfunction buildSlotSegLevels(segs) {\n\tvar levels = [];\n\tvar i, seg;\n\tvar j;\n\n\tfor (i=0; i<segs.length; i++) {\n\t\tseg = segs[i];\n\n\t\t// go through all the levels and stop on the first level where there are no collisions\n\t\tfor (j=0; j<levels.length; j++) {\n\t\t\tif (!computeSlotSegCollisions(seg, levels[j]).length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t(levels[j] || (levels[j] = [])).push(seg);\n\t}\n\n\treturn levels;\n}\n\n\n// For every segment, figure out the other segments that are in subsequent\n// levels that also occupy the same vertical space. Accumulate in seg.forwardSegs\nfunction computeForwardSlotSegs(levels) {\n\tvar i, level;\n\tvar j, seg;\n\tvar k;\n\n\tfor (i=0; i<levels.length; i++) {\n\t\tlevel = levels[i];\n\n\t\tfor (j=0; j<level.length; j++) {\n\t\t\tseg = level[j];\n\n\t\t\tseg.forwardSegs = [];\n\t\t\tfor (k=i+1; k<levels.length; k++) {\n\t\t\t\tcomputeSlotSegCollisions(seg, levels[k], seg.forwardSegs);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n// Figure out which path forward (via seg.forwardSegs) results in the longest path until\n// the furthest edge is reached. The number of segments in this path will be seg.forwardPressure\nfunction computeSlotSegPressures(seg) {\n\tvar forwardSegs = seg.forwardSegs;\n\tvar forwardPressure = 0;\n\tvar i, forwardSeg;\n\n\tif (seg.forwardPressure === undefined) { // not already computed\n\n\t\tfor (i=0; i<forwardSegs.length; i++) {\n\t\t\tforwardSeg = forwardSegs[i];\n\n\t\t\t// figure out the child's maximum forward path\n\t\t\tcomputeSlotSegPressures(forwardSeg);\n\n\t\t\t// either use the existing maximum, or use the child's forward pressure\n\t\t\t// plus one (for the forwardSeg itself)\n\t\t\tforwardPressure = Math.max(\n\t\t\t\tforwardPressure,\n\t\t\t\t1 + forwardSeg.forwardPressure\n\t\t\t);\n\t\t}\n\n\t\tseg.forwardPressure = forwardPressure;\n\t}\n}\n\n\n// Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range\n// from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to \"left\" and\n// seg.forwardCoord maps to \"right\" (via percentage). Vice-versa if the calendar is right-to-left.\n//\n// The segment might be part of a \"series\", which means consecutive segments with the same pressure\n// who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of\n// segments behind this one in the current series, and `seriesBackwardCoord` is the starting\n// coordinate of the first segment in the series.\nfunction computeSlotSegCoords(seg, seriesBackwardPressure, seriesBackwardCoord) {\n\tvar forwardSegs = seg.forwardSegs;\n\tvar i;\n\n\tif (seg.forwardCoord === undefined) { // not already computed\n\n\t\tif (!forwardSegs.length) {\n\n\t\t\t// if there are no forward segments, this segment should butt up against the edge\n\t\t\tseg.forwardCoord = 1;\n\t\t}\n\t\telse {\n\n\t\t\t// sort highest pressure first\n\t\t\tforwardSegs.sort(compareForwardSlotSegs);\n\n\t\t\t// this segment's forwardCoord will be calculated from the backwardCoord of the\n\t\t\t// highest-pressure forward segment.\n\t\t\tcomputeSlotSegCoords(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);\n\t\t\tseg.forwardCoord = forwardSegs[0].backwardCoord;\n\t\t}\n\n\t\t// calculate the backwardCoord from the forwardCoord. consider the series\n\t\tseg.backwardCoord = seg.forwardCoord -\n\t\t\t(seg.forwardCoord - seriesBackwardCoord) / // available width for series\n\t\t\t(seriesBackwardPressure + 1); // # of segments in the series\n\n\t\t// use this segment's coordinates to computed the coordinates of the less-pressurized\n\t\t// forward segments\n\t\tfor (i=0; i<forwardSegs.length; i++) {\n\t\t\tcomputeSlotSegCoords(forwardSegs[i], 0, seg.forwardCoord);\n\t\t}\n\t}\n}\n\n\n// Outputs a flat array of segments, from lowest to highest level\nfunction flattenSlotSegLevels(levels) {\n\tvar segs = [];\n\tvar i, level;\n\tvar j;\n\n\tfor (i=0; i<levels.length; i++) {\n\t\tlevel = levels[i];\n\n\t\tfor (j=0; j<level.length; j++) {\n\t\t\tsegs.push(level[j]);\n\t\t}\n\t}\n\n\treturn segs;\n}\n\n\n// Find all the segments in `otherSegs` that vertically collide with `seg`.\n// Append into an optionally-supplied `results` array and return.\nfunction computeSlotSegCollisions(seg, otherSegs, results) {\n\tresults = results || [];\n\n\tfor (var i=0; i<otherSegs.length; i++) {\n\t\tif (isSlotSegCollision(seg, otherSegs[i])) {\n\t\t\tresults.push(otherSegs[i]);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n\n// Do these segments occupy the same vertical space?\nfunction isSlotSegCollision(seg1, seg2) {\n\treturn seg1.end > seg2.start && seg1.start < seg2.end;\n}\n\n\n// A cmp function for determining which forward segment to rely on more when computing coordinates.\nfunction compareForwardSlotSegs(seg1, seg2) {\n\t// put higher-pressure first\n\treturn seg2.forwardPressure - seg1.forwardPressure ||\n\t\t// put segments that are closer to initial edge first (and favor ones with no coords yet)\n\t\t(seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||\n\t\t// do normal sorting...\n\t\tcompareSlotSegs(seg1, seg2);\n}\n\n\n// A cmp function for determining which segment should be closer to the initial edge\n// (the left edge on a left-to-right calendar).\nfunction compareSlotSegs(seg1, seg2) {\n\treturn seg1.start - seg2.start || // earlier start time goes first\n\t\t(seg2.end - seg2.start) - (seg1.end - seg1.start) || // tie? longer-duration goes first\n\t\t(seg1.event.title || '').localeCompare(seg2.event.title); // tie? alphabetically by title\n}\n\n\n;;\n\n\nfunction View(element, calendar, viewName) {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.element = element;\n\tt.calendar = calendar;\n\tt.name = viewName;\n\tt.opt = opt;\n\tt.trigger = trigger;\n\tt.isEventDraggable = isEventDraggable;\n\tt.isEventResizable = isEventResizable;\n\tt.setEventData = setEventData;\n\tt.clearEventData = clearEventData;\n\tt.eventEnd = eventEnd;\n\tt.reportEventElement = reportEventElement;\n\tt.triggerEventDestroy = triggerEventDestroy;\n\tt.eventElementHandlers = eventElementHandlers;\n\tt.showEvents = showEvents;\n\tt.hideEvents = hideEvents;\n\tt.eventDrop = eventDrop;\n\tt.eventResize = eventResize;\n\t// t.title\n\t// t.start, t.end\n\t// t.visStart, t.visEnd\n\t\n\t\n\t// imports\n\tvar defaultEventEnd = t.defaultEventEnd;\n\tvar normalizeEvent = calendar.normalizeEvent; // in EventManager\n\tvar reportEventChange = calendar.reportEventChange;\n\t\n\t\n\t// locals\n\tvar eventsByID = {}; // eventID mapped to array of events (there can be multiple b/c of repeating events)\n\tvar eventElementsByID = {}; // eventID mapped to array of jQuery elements\n\tvar eventElementCouples = []; // array of objects, { event, element } // TODO: unify with segment system\n\tvar options = calendar.options;\n\t\n\t\n\t\n\tfunction opt(name, viewNameOverride) {\n\t\tvar v = options[name];\n\t\tif ($.isPlainObject(v)) {\n\t\t\treturn smartProperty(v, viewNameOverride || viewName);\n\t\t}\n\t\treturn v;\n\t}\n\n\t\n\tfunction trigger(name, thisObj) {\n\t\treturn calendar.trigger.apply(\n\t\t\tcalendar,\n\t\t\t[name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])\n\t\t);\n\t}\n\t\n\n\n\t/* Event Editable Boolean Calculations\n\t------------------------------------------------------------------------------*/\n\n\t\n\tfunction isEventDraggable(event) {\n\t\tvar source = event.source || {};\n\t\treturn firstDefined(\n\t\t\t\tevent.startEditable,\n\t\t\t\tsource.startEditable,\n\t\t\t\topt('eventStartEditable'),\n\t\t\t\tevent.editable,\n\t\t\t\tsource.editable,\n\t\t\t\topt('editable')\n\t\t\t)\n\t\t\t&& !opt('disableDragging'); // deprecated\n\t}\n\t\n\t\n\tfunction isEventResizable(event) { // but also need to make sure the seg.isEnd == true\n\t\tvar source = event.source || {};\n\t\treturn firstDefined(\n\t\t\t\tevent.durationEditable,\n\t\t\t\tsource.durationEditable,\n\t\t\t\topt('eventDurationEditable'),\n\t\t\t\tevent.editable,\n\t\t\t\tsource.editable,\n\t\t\t\topt('editable')\n\t\t\t)\n\t\t\t&& !opt('disableResizing'); // deprecated\n\t}\n\t\n\t\n\t\n\t/* Event Data\n\t------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction setEventData(events) { // events are already normalized at this point\n\t\teventsByID = {};\n\t\tvar i, len=events.length, event;\n\t\tfor (i=0; i<len; i++) {\n\t\t\tevent = events[i];\n\t\t\tif (eventsByID[event._id]) {\n\t\t\t\teventsByID[event._id].push(event);\n\t\t\t}else{\n\t\t\t\teventsByID[event._id] = [event];\n\t\t\t}\n\t\t}\n\t}\n\n\n\tfunction clearEventData() {\n\t\teventsByID = {};\n\t\teventElementsByID = {};\n\t\teventElementCouples = [];\n\t}\n\t\n\t\n\t// returns a Date object for an event's end\n\tfunction eventEnd(event) {\n\t\treturn event.end ? cloneDate(event.end) : defaultEventEnd(event);\n\t}\n\t\n\t\n\t\n\t/* Event Elements\n\t------------------------------------------------------------------------------*/\n\t\n\t\n\t// report when view creates an element for an event\n\tfunction reportEventElement(event, element) {\n\t\teventElementCouples.push({ event: event, element: element });\n\t\tif (eventElementsByID[event._id]) {\n\t\t\teventElementsByID[event._id].push(element);\n\t\t}else{\n\t\t\teventElementsByID[event._id] = [element];\n\t\t}\n\t}\n\n\n\tfunction triggerEventDestroy() {\n\t\t$.each(eventElementCouples, function(i, couple) {\n\t\t\tt.trigger('eventDestroy', couple.event, couple.event, couple.element);\n\t\t});\n\t}\n\t\n\t\n\t// attaches eventClick, eventMouseover, eventMouseout\n\tfunction eventElementHandlers(event, eventElement) {\n\t\teventElement\n\t\t\t.click(function(ev) {\n\t\t\t\tif (!eventElement.hasClass('ui-draggable-dragging') &&\n\t\t\t\t\t!eventElement.hasClass('ui-resizable-resizing')) {\n\t\t\t\t\t\treturn trigger('eventClick', this, event, ev);\n\t\t\t\t\t}\n\t\t\t})\n\t\t\t.hover(\n\t\t\t\tfunction(ev) {\n\t\t\t\t\ttrigger('eventMouseover', this, event, ev);\n\t\t\t\t},\n\t\t\t\tfunction(ev) {\n\t\t\t\t\ttrigger('eventMouseout', this, event, ev);\n\t\t\t\t}\n\t\t\t);\n\t\t// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)\n\t\t// TODO: same for resizing\n\t}\n\t\n\t\n\tfunction showEvents(event, exceptElement) {\n\t\teachEventElement(event, exceptElement, 'show');\n\t}\n\t\n\t\n\tfunction hideEvents(event, exceptElement) {\n\t\teachEventElement(event, exceptElement, 'hide');\n\t}\n\t\n\t\n\tfunction eachEventElement(event, exceptElement, funcName) {\n\t\t// NOTE: there may be multiple events per ID (repeating events)\n\t\t// and multiple segments per event\n\t\tvar elements = eventElementsByID[event._id],\n\t\t\ti, len = elements.length;\n\t\tfor (i=0; i<len; i++) {\n\t\t\tif (!exceptElement || elements[i][0] != exceptElement[0]) {\n\t\t\t\telements[i][funcName]();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/* Event Modification Reporting\n\t---------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {\n\t\tvar oldAllDay = event.allDay;\n\t\tvar eventId = event._id;\n\t\tmoveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);\n\t\ttrigger(\n\t\t\t'eventDrop',\n\t\t\te,\n\t\t\tevent,\n\t\t\tdayDelta,\n\t\t\tminuteDelta,\n\t\t\tallDay,\n\t\t\tfunction() {\n\t\t\t\t// TODO: investigate cases where this inverse technique might not work\n\t\t\t\tmoveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);\n\t\t\t\treportEventChange(eventId);\n\t\t\t},\n\t\t\tev,\n\t\t\tui\n\t\t);\n\t\treportEventChange(eventId);\n\t}\n\t\n\t\n\tfunction eventResize(e, event, dayDelta, minuteDelta, ev, ui) {\n\t\tvar eventId = event._id;\n\t\telongateEvents(eventsByID[eventId], dayDelta, minuteDelta);\n\t\ttrigger(\n\t\t\t'eventResize',\n\t\t\te,\n\t\t\tevent,\n\t\t\tdayDelta,\n\t\t\tminuteDelta,\n\t\t\tfunction() {\n\t\t\t\t// TODO: investigate cases where this inverse technique might not work\n\t\t\t\telongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);\n\t\t\t\treportEventChange(eventId);\n\t\t\t},\n\t\t\tev,\n\t\t\tui\n\t\t);\n\t\treportEventChange(eventId);\n\t}\n\t\n\t\n\t\n\t/* Event Modification Math\n\t---------------------------------------------------------------------------------*/\n\t\n\t\n\tfunction moveEvents(events, dayDelta, minuteDelta, allDay) {\n\t\tminuteDelta = minuteDelta || 0;\n\t\tfor (var e, len=events.length, i=0; i<len; i++) {\n\t\t\te = events[i];\n\t\t\tif (allDay !== undefined) {\n\t\t\t\te.allDay = allDay;\n\t\t\t}\n\t\t\taddMinutes(addDays(e.start, dayDelta, true), minuteDelta);\n\t\t\tif (e.end) {\n\t\t\t\te.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);\n\t\t\t}\n\t\t\tnormalizeEvent(e, options);\n\t\t}\n\t}\n\t\n\t\n\tfunction elongateEvents(events, dayDelta, minuteDelta) {\n\t\tminuteDelta = minuteDelta || 0;\n\t\tfor (var e, len=events.length, i=0; i<len; i++) {\n\t\t\te = events[i];\n\t\t\te.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);\n\t\t\tnormalizeEvent(e, options);\n\t\t}\n\t}\n\n\n\n\t// ====================================================================================================\n\t// Utilities for day \"cells\"\n\t// ====================================================================================================\n\t// The \"basic\" views are completely made up of day cells.\n\t// The \"agenda\" views have day cells at the top \"all day\" slot.\n\t// This was the obvious common place to put these utilities, but they should be abstracted out into\n\t// a more meaningful class (like DayEventRenderer).\n\t// ====================================================================================================\n\n\n\t// For determining how a given \"cell\" translates into a \"date\":\n\t//\n\t// 1. Convert the \"cell\" (row and column) into a \"cell offset\" (the # of the cell, cronologically from the first).\n\t//    Keep in mind that column indices are inverted with isRTL. This is taken into account.\n\t//\n\t// 2. Convert the \"cell offset\" to a \"day offset\" (the # of days since the first visible day in the view).\n\t//\n\t// 3. Convert the \"day offset\" into a \"date\" (a JavaScript Date object).\n\t//\n\t// The reverse transformation happens when transforming a date into a cell.\n\n\n\t// exports\n\tt.isHiddenDay = isHiddenDay;\n\tt.skipHiddenDays = skipHiddenDays;\n\tt.getCellsPerWeek = getCellsPerWeek;\n\tt.dateToCell = dateToCell;\n\tt.dateToDayOffset = dateToDayOffset;\n\tt.dayOffsetToCellOffset = dayOffsetToCellOffset;\n\tt.cellOffsetToCell = cellOffsetToCell;\n\tt.cellToDate = cellToDate;\n\tt.cellToCellOffset = cellToCellOffset;\n\tt.cellOffsetToDayOffset = cellOffsetToDayOffset;\n\tt.dayOffsetToDate = dayOffsetToDate;\n\tt.rangeToSegments = rangeToSegments;\n\n\n\t// internals\n\tvar hiddenDays = opt('hiddenDays') || []; // array of day-of-week indices that are hidden\n\tvar isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)\n\tvar cellsPerWeek;\n\tvar dayToCellMap = []; // hash from dayIndex -> cellIndex, for one week\n\tvar cellToDayMap = []; // hash from cellIndex -> dayIndex, for one week\n\tvar isRTL = opt('isRTL');\n\n\n\t// initialize important internal variables\n\t(function() {\n\n\t\tif (opt('weekends') === false) {\n\t\t\thiddenDays.push(0, 6); // 0=sunday, 6=saturday\n\t\t}\n\n\t\t// Loop through a hypothetical week and determine which\n\t\t// days-of-week are hidden. Record in both hashes (one is the reverse of the other).\n\t\tfor (var dayIndex=0, cellIndex=0; dayIndex<7; dayIndex++) {\n\t\t\tdayToCellMap[dayIndex] = cellIndex;\n\t\t\tisHiddenDayHash[dayIndex] = $.inArray(dayIndex, hiddenDays) != -1;\n\t\t\tif (!isHiddenDayHash[dayIndex]) {\n\t\t\t\tcellToDayMap[cellIndex] = dayIndex;\n\t\t\t\tcellIndex++;\n\t\t\t}\n\t\t}\n\n\t\tcellsPerWeek = cellIndex;\n\t\tif (!cellsPerWeek) {\n\t\t\tthrow 'invalid hiddenDays'; // all days were hidden? bad.\n\t\t}\n\n\t})();\n\n\n\t// Is the current day hidden?\n\t// `day` is a day-of-week index (0-6), or a Date object\n\tfunction isHiddenDay(day) {\n\t\tif (typeof day == 'object') {\n\t\t\tday = day.getDay();\n\t\t}\n\t\treturn isHiddenDayHash[day];\n\t}\n\n\n\tfunction getCellsPerWeek() {\n\t\treturn cellsPerWeek;\n\t}\n\n\n\t// Keep incrementing the current day until it is no longer a hidden day.\n\t// If the initial value of `date` is not a hidden day, don't do anything.\n\t// Pass `isExclusive` as `true` if you are dealing with an end date.\n\t// `inc` defaults to `1` (increment one day forward each time)\n\tfunction skipHiddenDays(date, inc, isExclusive) {\n\t\tinc = inc || 1;\n\t\twhile (\n\t\t\tisHiddenDayHash[ ( date.getDay() + (isExclusive ? inc : 0) + 7 ) % 7 ]\n\t\t) {\n\t\t\taddDays(date, inc);\n\t\t}\n\t}\n\n\n\t//\n\t// TRANSFORMATIONS: cell -> cell offset -> day offset -> date\n\t//\n\n\t// cell -> date (combines all transformations)\n\t// Possible arguments:\n\t// - row, col\n\t// - { row:#, col: # }\n\tfunction cellToDate() {\n\t\tvar cellOffset = cellToCellOffset.apply(null, arguments);\n\t\tvar dayOffset = cellOffsetToDayOffset(cellOffset);\n\t\tvar date = dayOffsetToDate(dayOffset);\n\t\treturn date;\n\t}\n\n\t// cell -> cell offset\n\t// Possible arguments:\n\t// - row, col\n\t// - { row:#, col:# }\n\tfunction cellToCellOffset(row, col) {\n\t\tvar colCnt = t.getColCnt();\n\n\t\t// rtl variables. wish we could pre-populate these. but where?\n\t\tvar dis = isRTL ? -1 : 1;\n\t\tvar dit = isRTL ? colCnt - 1 : 0;\n\n\t\tif (typeof row == 'object') {\n\t\t\tcol = row.col;\n\t\t\trow = row.row;\n\t\t}\n\t\tvar cellOffset = row * colCnt + (col * dis + dit); // column, adjusted for RTL (dis & dit)\n\n\t\treturn cellOffset;\n\t}\n\n\t// cell offset -> day offset\n\tfunction cellOffsetToDayOffset(cellOffset) {\n\t\tvar day0 = t.visStart.getDay(); // first date's day of week\n\t\tcellOffset += dayToCellMap[day0]; // normlize cellOffset to beginning-of-week\n\t\treturn Math.floor(cellOffset / cellsPerWeek) * 7 // # of days from full weeks\n\t\t\t+ cellToDayMap[ // # of days from partial last week\n\t\t\t\t(cellOffset % cellsPerWeek + cellsPerWeek) % cellsPerWeek // crazy math to handle negative cellOffsets\n\t\t\t]\n\t\t\t- day0; // adjustment for beginning-of-week normalization\n\t}\n\n\t// day offset -> date (JavaScript Date object)\n\tfunction dayOffsetToDate(dayOffset) {\n\t\tvar date = cloneDate(t.visStart);\n\t\taddDays(date, dayOffset);\n\t\treturn date;\n\t}\n\n\n\t//\n\t// TRANSFORMATIONS: date -> day offset -> cell offset -> cell\n\t//\n\n\t// date -> cell (combines all transformations)\n\tfunction dateToCell(date) {\n\t\tvar dayOffset = dateToDayOffset(date);\n\t\tvar cellOffset = dayOffsetToCellOffset(dayOffset);\n\t\tvar cell = cellOffsetToCell(cellOffset);\n\t\treturn cell;\n\t}\n\n\t// date -> day offset\n\tfunction dateToDayOffset(date) {\n\t\treturn dayDiff(date, t.visStart);\n\t}\n\n\t// day offset -> cell offset\n\tfunction dayOffsetToCellOffset(dayOffset) {\n\t\tvar day0 = t.visStart.getDay(); // first date's day of week\n\t\tdayOffset += day0; // normalize dayOffset to beginning-of-week\n\t\treturn Math.floor(dayOffset / 7) * cellsPerWeek // # of cells from full weeks\n\t\t\t+ dayToCellMap[ // # of cells from partial last week\n\t\t\t\t(dayOffset % 7 + 7) % 7 // crazy math to handle negative dayOffsets\n\t\t\t]\n\t\t\t- dayToCellMap[day0]; // adjustment for beginning-of-week normalization\n\t}\n\n\t// cell offset -> cell (object with row & col keys)\n\tfunction cellOffsetToCell(cellOffset) {\n\t\tvar colCnt = t.getColCnt();\n\n\t\t// rtl variables. wish we could pre-populate these. but where?\n\t\tvar dis = isRTL ? -1 : 1;\n\t\tvar dit = isRTL ? colCnt - 1 : 0;\n\n\t\tvar row = Math.floor(cellOffset / colCnt);\n\t\tvar col = ((cellOffset % colCnt + colCnt) % colCnt) * dis + dit; // column, adjusted for RTL (dis & dit)\n\t\treturn {\n\t\t\trow: row,\n\t\t\tcol: col\n\t\t};\n\t}\n\n\n\t//\n\t// Converts a date range into an array of segment objects.\n\t// \"Segments\" are horizontal stretches of time, sliced up by row.\n\t// A segment object has the following properties:\n\t// - row\n\t// - cols\n\t// - isStart\n\t// - isEnd\n\t//\n\tfunction rangeToSegments(startDate, endDate) {\n\t\tvar rowCnt = t.getRowCnt();\n\t\tvar colCnt = t.getColCnt();\n\t\tvar segments = []; // array of segments to return\n\n\t\t// day offset for given date range\n\t\tvar rangeDayOffsetStart = dateToDayOffset(startDate);\n\t\tvar rangeDayOffsetEnd = dateToDayOffset(endDate); // exclusive\n\n\t\t// first and last cell offset for the given date range\n\t\t// \"last\" implies inclusivity\n\t\tvar rangeCellOffsetFirst = dayOffsetToCellOffset(rangeDayOffsetStart);\n\t\tvar rangeCellOffsetLast = dayOffsetToCellOffset(rangeDayOffsetEnd) - 1;\n\n\t\t// loop through all the rows in the view\n\t\tfor (var row=0; row<rowCnt; row++) {\n\n\t\t\t// first and last cell offset for the row\n\t\t\tvar rowCellOffsetFirst = row * colCnt;\n\t\t\tvar rowCellOffsetLast = rowCellOffsetFirst + colCnt - 1;\n\n\t\t\t// get the segment's cell offsets by constraining the range's cell offsets to the bounds of the row\n\t\t\tvar segmentCellOffsetFirst = Math.max(rangeCellOffsetFirst, rowCellOffsetFirst);\n\t\t\tvar segmentCellOffsetLast = Math.min(rangeCellOffsetLast, rowCellOffsetLast);\n\n\t\t\t// make sure segment's offsets are valid and in view\n\t\t\tif (segmentCellOffsetFirst <= segmentCellOffsetLast) {\n\n\t\t\t\t// translate to cells\n\t\t\t\tvar segmentCellFirst = cellOffsetToCell(segmentCellOffsetFirst);\n\t\t\t\tvar segmentCellLast = cellOffsetToCell(segmentCellOffsetLast);\n\n\t\t\t\t// view might be RTL, so order by leftmost column\n\t\t\t\tvar cols = [ segmentCellFirst.col, segmentCellLast.col ].sort();\n\n\t\t\t\t// Determine if segment's first/last cell is the beginning/end of the date range.\n\t\t\t\t// We need to compare \"day offset\" because \"cell offsets\" are often ambiguous and\n\t\t\t\t// can translate to multiple days, and an edge case reveals itself when we the\n\t\t\t\t// range's first cell is hidden (we don't want isStart to be true).\n\t\t\t\tvar isStart = cellOffsetToDayOffset(segmentCellOffsetFirst) == rangeDayOffsetStart;\n\t\t\t\tvar isEnd = cellOffsetToDayOffset(segmentCellOffsetLast) + 1 == rangeDayOffsetEnd; // +1 for comparing exclusively\n\n\t\t\t\tsegments.push({\n\t\t\t\t\trow: row,\n\t\t\t\t\tleftCol: cols[0],\n\t\t\t\t\trightCol: cols[1],\n\t\t\t\t\tisStart: isStart,\n\t\t\t\t\tisEnd: isEnd\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn segments;\n\t}\n\t\n\n}\n\n;;\n\nfunction DayEventRenderer() {\n\tvar t = this;\n\n\t\n\t// exports\n\tt.renderDayEvents = renderDayEvents;\n\tt.draggableDayEvent = draggableDayEvent; // made public so that subclasses can override\n\tt.resizableDayEvent = resizableDayEvent; // \"\n\t\n\t\n\t// imports\n\tvar opt = t.opt;\n\tvar trigger = t.trigger;\n\tvar isEventDraggable = t.isEventDraggable;\n\tvar isEventResizable = t.isEventResizable;\n\tvar eventEnd = t.eventEnd;\n\tvar reportEventElement = t.reportEventElement;\n\tvar eventElementHandlers = t.eventElementHandlers;\n\tvar showEvents = t.showEvents;\n\tvar hideEvents = t.hideEvents;\n\tvar eventDrop = t.eventDrop;\n\tvar eventResize = t.eventResize;\n\tvar getRowCnt = t.getRowCnt;\n\tvar getColCnt = t.getColCnt;\n\tvar getColWidth = t.getColWidth;\n\tvar allDayRow = t.allDayRow; // TODO: rename\n\tvar colLeft = t.colLeft;\n\tvar colRight = t.colRight;\n\tvar colContentLeft = t.colContentLeft;\n\tvar colContentRight = t.colContentRight;\n\tvar dateToCell = t.dateToCell;\n\tvar getDaySegmentContainer = t.getDaySegmentContainer;\n\tvar formatDates = t.calendar.formatDates;\n\tvar renderDayOverlay = t.renderDayOverlay;\n\tvar clearOverlays = t.clearOverlays;\n\tvar clearSelection = t.clearSelection;\n\tvar getHoverListener = t.getHoverListener;\n\tvar rangeToSegments = t.rangeToSegments;\n\tvar cellToDate = t.cellToDate;\n\tvar cellToCellOffset = t.cellToCellOffset;\n\tvar cellOffsetToDayOffset = t.cellOffsetToDayOffset;\n\tvar dateToDayOffset = t.dateToDayOffset;\n\tvar dayOffsetToCellOffset = t.dayOffsetToCellOffset;\n\n\n\t// Render `events` onto the calendar, attach mouse event handlers, and call the `eventAfterRender` callback for each.\n\t// Mouse event will be lazily applied, except if the event has an ID of `modifiedEventId`.\n\t// Can only be called when the event container is empty (because it wipes out all innerHTML).\n\tfunction renderDayEvents(events, modifiedEventId) {\n\n\t\t// do the actual rendering. Receive the intermediate \"segment\" data structures.\n\t\tvar segments = _renderDayEvents(\n\t\t\tevents,\n\t\t\tfalse, // don't append event elements\n\t\t\ttrue // set the heights of the rows\n\t\t);\n\n\t\t// report the elements to the View, for general drag/resize utilities\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\treportEventElement(segment.event, element);\n\t\t});\n\n\t\t// attach mouse handlers\n\t\tattachHandlers(segments, modifiedEventId);\n\n\t\t// call `eventAfterRender` callback for each event\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\ttrigger('eventAfterRender', segment.event, segment.event, element);\n\t\t});\n\t}\n\n\n\t// Render an event on the calendar, but don't report them anywhere, and don't attach mouse handlers.\n\t// Append this event element to the event container, which might already be populated with events.\n\t// If an event's segment will have row equal to `adjustRow`, then explicitly set its top coordinate to `adjustTop`.\n\t// This hack is used to maintain continuity when user is manually resizing an event.\n\t// Returns an array of DOM elements for the event.\n\tfunction renderTempDayEvent(event, adjustRow, adjustTop) {\n\n\t\t// actually render the event. `true` for appending element to container.\n\t\t// Recieve the intermediate \"segment\" data structures.\n\t\tvar segments = _renderDayEvents(\n\t\t\t[ event ],\n\t\t\ttrue, // append event elements\n\t\t\tfalse // don't set the heights of the rows\n\t\t);\n\n\t\tvar elements = [];\n\n\t\t// Adjust certain elements' top coordinates\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\tif (segment.row === adjustRow) {\n\t\t\t\telement.css('top', adjustTop);\n\t\t\t}\n\t\t\telements.push(element[0]); // accumulate DOM nodes\n\t\t});\n\n\t\treturn elements;\n\t}\n\n\n\t// Render events onto the calendar. Only responsible for the VISUAL aspect.\n\t// Not responsible for attaching handlers or calling callbacks.\n\t// Set `doAppend` to `true` for rendering elements without clearing the existing container.\n\t// Set `doRowHeights` to allow setting the height of each row, to compensate for vertical event overflow.\n\tfunction _renderDayEvents(events, doAppend, doRowHeights) {\n\n\t\t// where the DOM nodes will eventually end up\n\t\tvar finalContainer = getDaySegmentContainer();\n\n\t\t// the container where the initial HTML will be rendered.\n\t\t// If `doAppend`==true, uses a temporary container.\n\t\tvar renderContainer = doAppend ? $(\"<div/>\") : finalContainer;\n\n\t\tvar segments = buildSegments(events);\n\t\tvar html;\n\t\tvar elements;\n\n\t\t// calculate the desired `left` and `width` properties on each segment object\n\t\tcalculateHorizontals(segments);\n\n\t\t// build the HTML string. relies on `left` property\n\t\thtml = buildHTML(segments);\n\n\t\t// render the HTML. innerHTML is considerably faster than jQuery's .html()\n\t\trenderContainer[0].innerHTML = html;\n\n\t\t// retrieve the individual elements\n\t\telements = renderContainer.children();\n\n\t\t// if we were appending, and thus using a temporary container,\n\t\t// re-attach elements to the real container.\n\t\tif (doAppend) {\n\t\t\tfinalContainer.append(elements);\n\t\t}\n\n\t\t// assigns each element to `segment.event`, after filtering them through user callbacks\n\t\tresolveElements(segments, elements);\n\n\t\t// Calculate the left and right padding+margin for each element.\n\t\t// We need this for setting each element's desired outer width, because of the W3C box model.\n\t\t// It's important we do this in a separate pass from acually setting the width on the DOM elements\n\t\t// because alternating reading/writing dimensions causes reflow for every iteration.\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\tsegment.hsides = hsides(element, true); // include margins = `true`\n\t\t});\n\n\t\t// Set the width of each element\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\telement.width(\n\t\t\t\tMath.max(0, segment.outerWidth - segment.hsides)\n\t\t\t);\n\t\t});\n\n\t\t// Grab each element's outerHeight (setVerticals uses this).\n\t\t// To get an accurate reading, it's important to have each element's width explicitly set already.\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\tsegment.outerHeight = element.outerHeight(true); // include margins = `true`\n\t\t});\n\n\t\t// Set the top coordinate on each element (requires segment.outerHeight)\n\t\tsetVerticals(segments, doRowHeights);\n\n\t\treturn segments;\n\t}\n\n\n\t// Generate an array of \"segments\" for all events.\n\tfunction buildSegments(events) {\n\t\tvar segments = [];\n\t\tfor (var i=0; i<events.length; i++) {\n\t\t\tvar eventSegments = buildSegmentsForEvent(events[i]);\n\t\t\tsegments.push.apply(segments, eventSegments); // append an array to an array\n\t\t}\n\t\treturn segments;\n\t}\n\n\n\t// Generate an array of segments for a single event.\n\t// A \"segment\" is the same data structure that View.rangeToSegments produces,\n\t// with the addition of the `event` property being set to reference the original event.\n\tfunction buildSegmentsForEvent(event) {\n\t\tvar startDate = event.start;\n\t\tvar endDate = exclEndDay(event);\n\t\tvar segments = rangeToSegments(startDate, endDate);\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tsegments[i].event = event;\n\t\t}\n\t\treturn segments;\n\t}\n\n\n\t// Sets the `left` and `outerWidth` property of each segment.\n\t// These values are the desired dimensions for the eventual DOM elements.\n\tfunction calculateHorizontals(segments) {\n\t\tvar isRTL = opt('isRTL');\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tvar segment = segments[i];\n\n\t\t\t// Determine functions used for calulating the elements left/right coordinates,\n\t\t\t// depending on whether the view is RTL or not.\n\t\t\t// NOTE:\n\t\t\t// colLeft/colRight returns the coordinate butting up the edge of the cell.\n\t\t\t// colContentLeft/colContentRight is indented a little bit from the edge.\n\t\t\tvar leftFunc = (isRTL ? segment.isEnd : segment.isStart) ? colContentLeft : colLeft;\n\t\t\tvar rightFunc = (isRTL ? segment.isStart : segment.isEnd) ? colContentRight : colRight;\n\n\t\t\tvar left = leftFunc(segment.leftCol);\n\t\t\tvar right = rightFunc(segment.rightCol);\n\t\t\tsegment.left = left;\n\t\t\tsegment.outerWidth = right - left;\n\t\t}\n\t}\n\n\n\t// Build a concatenated HTML string for an array of segments\n\tfunction buildHTML(segments) {\n\t\tvar html = '';\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\thtml += buildHTMLForSegment(segments[i]);\n\t\t}\n\t\treturn html;\n\t}\n\n\n\t// Build an HTML string for a single segment.\n\t// Relies on the following properties:\n\t// - `segment.event` (from `buildSegmentsForEvent`)\n\t// - `segment.left` (from `calculateHorizontals`)\n\tfunction buildHTMLForSegment(segment) {\n\t\tvar html = '';\n\t\tvar isRTL = opt('isRTL');\n\t\tvar event = segment.event;\n\t\tvar url = event.url;\n\n\t\t// generate the list of CSS classNames\n\t\tvar classNames = [ 'fc-event', 'fc-event-hori' ];\n\t\tif (isEventDraggable(event)) {\n\t\t\tclassNames.push('fc-event-draggable');\n\t\t}\n\t\tif (segment.isStart) {\n\t\t\tclassNames.push('fc-event-start');\n\t\t}\n\t\tif (segment.isEnd) {\n\t\t\tclassNames.push('fc-event-end');\n\t\t}\n\t\t// use the event's configured classNames\n\t\t// guaranteed to be an array via `normalizeEvent`\n\t\tclassNames = classNames.concat(event.className);\n\t\tif (event.source) {\n\t\t\t// use the event's source's classNames, if specified\n\t\t\tclassNames = classNames.concat(event.source.className || []);\n\t\t}\n\n\t\t// generate a semicolon delimited CSS string for any of the \"skin\" properties\n\t\t// of the event object (`backgroundColor`, `borderColor` and such)\n\t\tvar skinCss = getSkinCss(event, opt);\n\n\t\tif (url) {\n\t\t\thtml += \"<a href='\" + htmlEscape(url) + \"'\";\n\t\t}else{\n\t\t\thtml += \"<div\";\n\t\t}\n\t\thtml +=\n\t\t\t\" class='\" + classNames.join(' ') + \"'\" +\n\t\t\t\" style=\" +\n\t\t\t\t\"'\" +\n\t\t\t\t\"position:absolute;\" +\n\t\t\t\t\"left:\" + segment.left + \"px;\" +\n\t\t\t\tskinCss +\n\t\t\t\t\"'\" +\n\t\t\t\">\" +\n\t\t\t\"<div class='fc-event-inner'>\";\n\t\tif (!event.allDay && segment.isStart) {\n\t\t\thtml +=\n\t\t\t\t\"<span class='fc-event-time'>\" +\n\t\t\t\thtmlEscape(\n\t\t\t\t\tformatDates(event.start, event.end, opt('timeFormat'))\n\t\t\t\t) +\n\t\t\t\t\"</span>\";\n\t\t}\n\t\thtml +=\n\t\t\t\"<span class='fc-event-title'>\" +\n\t\t\thtmlEscape(event.title || '') +\n\t\t\t\"</span>\" +\n\t\t\t\"</div>\";\n\t\tif (segment.isEnd && isEventResizable(event)) {\n\t\t\thtml +=\n\t\t\t\t\"<div class='ui-resizable-handle ui-resizable-\" + (isRTL ? 'w' : 'e') + \"'>\" +\n\t\t\t\t\"&nbsp;&nbsp;&nbsp;\" + // makes hit area a lot better for IE6/7\n\t\t\t\t\"</div>\";\n\t\t}\n\t\thtml += \"</\" + (url ? \"a\" : \"div\") + \">\";\n\n\t\t// TODO:\n\t\t// When these elements are initially rendered, they will be briefly visibile on the screen,\n\t\t// even though their widths/heights are not set.\n\t\t// SOLUTION: initially set them as visibility:hidden ?\n\n\t\treturn html;\n\t}\n\n\n\t// Associate each segment (an object) with an element (a jQuery object),\n\t// by setting each `segment.element`.\n\t// Run each element through the `eventRender` filter, which allows developers to\n\t// modify an existing element, supply a new one, or cancel rendering.\n\tfunction resolveElements(segments, elements) {\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tvar segment = segments[i];\n\t\t\tvar event = segment.event;\n\t\t\tvar element = elements.eq(i);\n\n\t\t\t// call the trigger with the original element\n\t\t\tvar triggerRes = trigger('eventRender', event, event, element);\n\n\t\t\tif (triggerRes === false) {\n\t\t\t\t// if `false`, remove the event from the DOM and don't assign it to `segment.event`\n\t\t\t\telement.remove();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (triggerRes && triggerRes !== true) {\n\t\t\t\t\t// the trigger returned a new element, but not `true` (which means keep the existing element)\n\n\t\t\t\t\t// re-assign the important CSS dimension properties that were already assigned in `buildHTMLForSegment`\n\t\t\t\t\ttriggerRes = $(triggerRes)\n\t\t\t\t\t\t.css({\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\tleft: segment.left\n\t\t\t\t\t\t});\n\n\t\t\t\t\telement.replaceWith(triggerRes);\n\t\t\t\t\telement = triggerRes;\n\t\t\t\t}\n\n\t\t\t\tsegment.element = element;\n\t\t\t}\n\t\t}\n\t}\n\n\n\n\t/* Top-coordinate Methods\n\t-------------------------------------------------------------------------------------------------*/\n\n\n\t// Sets the \"top\" CSS property for each element.\n\t// If `doRowHeights` is `true`, also sets each row's first cell to an explicit height,\n\t// so that if elements vertically overflow, the cell expands vertically to compensate.\n\tfunction setVerticals(segments, doRowHeights) {\n\t\tvar rowContentHeights = calculateVerticals(segments); // also sets segment.top\n\t\tvar rowContentElements = getRowContentElements(); // returns 1 inner div per row\n\t\tvar rowContentTops = [];\n\n\t\t// Set each row's height by setting height of first inner div\n\t\tif (doRowHeights) {\n\t\t\tfor (var i=0; i<rowContentElements.length; i++) {\n\t\t\t\trowContentElements[i].height(rowContentHeights[i]);\n\t\t\t}\n\t\t}\n\n\t\t// Get each row's top, relative to the views's origin.\n\t\t// Important to do this after setting each row's height.\n\t\tfor (var i=0; i<rowContentElements.length; i++) {\n\t\t\trowContentTops.push(\n\t\t\t\trowContentElements[i].position().top\n\t\t\t);\n\t\t}\n\n\t\t// Set each segment element's CSS \"top\" property.\n\t\t// Each segment object has a \"top\" property, which is relative to the row's top, but...\n\t\tsegmentElementEach(segments, function(segment, element) {\n\t\t\telement.css(\n\t\t\t\t'top',\n\t\t\t\trowContentTops[segment.row] + segment.top // ...now, relative to views's origin\n\t\t\t);\n\t\t});\n\t}\n\n\n\t// Calculate the \"top\" coordinate for each segment, relative to the \"top\" of the row.\n\t// Also, return an array that contains the \"content\" height for each row\n\t// (the height displaced by the vertically stacked events in the row).\n\t// Requires segments to have their `outerHeight` property already set.\n\tfunction calculateVerticals(segments) {\n\t\tvar rowCnt = getRowCnt();\n\t\tvar colCnt = getColCnt();\n\t\tvar rowContentHeights = []; // content height for each row\n\t\tvar segmentRows = buildSegmentRows(segments); // an array of segment arrays, one for each row\n\n\t\tfor (var rowI=0; rowI<rowCnt; rowI++) {\n\t\t\tvar segmentRow = segmentRows[rowI];\n\n\t\t\t// an array of running total heights for each column.\n\t\t\t// initialize with all zeros.\n\t\t\tvar colHeights = [];\n\t\t\tfor (var colI=0; colI<colCnt; colI++) {\n\t\t\t\tcolHeights.push(0);\n\t\t\t}\n\n\t\t\t// loop through every segment\n\t\t\tfor (var segmentI=0; segmentI<segmentRow.length; segmentI++) {\n\t\t\t\tvar segment = segmentRow[segmentI];\n\n\t\t\t\t// find the segment's top coordinate by looking at the max height\n\t\t\t\t// of all the columns the segment will be in.\n\t\t\t\tsegment.top = arrayMax(\n\t\t\t\t\tcolHeights.slice(\n\t\t\t\t\t\tsegment.leftCol,\n\t\t\t\t\t\tsegment.rightCol + 1 // make exclusive for slice\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\t\t// adjust the columns to account for the segment's height\n\t\t\t\tfor (var colI=segment.leftCol; colI<=segment.rightCol; colI++) {\n\t\t\t\t\tcolHeights[colI] = segment.top + segment.outerHeight;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// the tallest column in the row should be the \"content height\"\n\t\t\trowContentHeights.push(arrayMax(colHeights));\n\t\t}\n\n\t\treturn rowContentHeights;\n\t}\n\n\n\t// Build an array of segment arrays, each representing the segments that will\n\t// be in a row of the grid, sorted by which event should be closest to the top.\n\tfunction buildSegmentRows(segments) {\n\t\tvar rowCnt = getRowCnt();\n\t\tvar segmentRows = [];\n\t\tvar segmentI;\n\t\tvar segment;\n\t\tvar rowI;\n\n\t\t// group segments by row\n\t\tfor (segmentI=0; segmentI<segments.length; segmentI++) {\n\t\t\tsegment = segments[segmentI];\n\t\t\trowI = segment.row;\n\t\t\tif (segment.element) { // was rendered?\n\t\t\t\tif (segmentRows[rowI]) {\n\t\t\t\t\t// already other segments. append to array\n\t\t\t\t\tsegmentRows[rowI].push(segment);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// first segment in row. create new array\n\t\t\t\t\tsegmentRows[rowI] = [ segment ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sort each row\n\t\tfor (rowI=0; rowI<rowCnt; rowI++) {\n\t\t\tsegmentRows[rowI] = sortSegmentRow(\n\t\t\t\tsegmentRows[rowI] || [] // guarantee an array, even if no segments\n\t\t\t);\n\t\t}\n\n\t\treturn segmentRows;\n\t}\n\n\n\t// Sort an array of segments according to which segment should appear closest to the top\n\tfunction sortSegmentRow(segments) {\n\t\tvar sortedSegments = [];\n\n\t\t// build the subrow array\n\t\tvar subrows = buildSegmentSubrows(segments);\n\n\t\t// flatten it\n\t\tfor (var i=0; i<subrows.length; i++) {\n\t\t\tsortedSegments.push.apply(sortedSegments, subrows[i]); // append an array to an array\n\t\t}\n\n\t\treturn sortedSegments;\n\t}\n\n\n\t// Take an array of segments, which are all assumed to be in the same row,\n\t// and sort into subrows.\n\tfunction buildSegmentSubrows(segments) {\n\n\t\t// Give preference to elements with certain criteria, so they have\n\t\t// a chance to be closer to the top.\n\t\tsegments.sort(compareDaySegments);\n\n\t\tvar subrows = [];\n\t\tfor (var i=0; i<segments.length; i++) {\n\t\t\tvar segment = segments[i];\n\n\t\t\t// loop through subrows, starting with the topmost, until the segment\n\t\t\t// doesn't collide with other segments.\n\t\t\tfor (var j=0; j<subrows.length; j++) {\n\t\t\t\tif (!isDaySegmentCollision(segment, subrows[j])) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// `j` now holds the desired subrow index\n\t\t\tif (subrows[j]) {\n\t\t\t\tsubrows[j].push(segment);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsubrows[j] = [ segment ];\n\t\t\t}\n\t\t}\n\n\t\treturn subrows;\n\t}\n\n\n\t// Return an array of jQuery objects for the placeholder content containers of each row.\n\t// The content containers don't actually contain anything, but their dimensions should match\n\t// the events that are overlaid on top.\n\tfunction getRowContentElements() {\n\t\tvar i;\n\t\tvar rowCnt = getRowCnt();\n\t\tvar rowDivs = [];\n\t\tfor (i=0; i<rowCnt; i++) {\n\t\t\trowDivs[i] = allDayRow(i)\n\t\t\t\t.find('div.fc-day-content > div');\n\t\t}\n\t\treturn rowDivs;\n\t}\n\n\n\n\t/* Mouse Handlers\n\t---------------------------------------------------------------------------------------------------*/\n\t// TODO: better documentation!\n\n\n\tfunction attachHandlers(segments, modifiedEventId) {\n\t\tvar segmentContainer = getDaySegmentContainer();\n\n\t\tsegmentElementEach(segments, function(segment, element, i) {\n\t\t\tvar event = segment.event;\n\t\t\tif (event._id === modifiedEventId) {\n\t\t\t\tbindDaySeg(event, element, segment);\n\t\t\t}else{\n\t\t\t\telement[0]._fci = i; // for lazySegBind\n\t\t\t}\n\t\t});\n\n\t\tlazySegBind(segmentContainer, segments, bindDaySeg);\n\t}\n\n\n\tfunction bindDaySeg(event, eventElement, segment) {\n\n\t\tif (isEventDraggable(event)) {\n\t\t\tt.draggableDayEvent(event, eventElement, segment); // use `t` so subclasses can override\n\t\t}\n\n\t\tif (\n\t\t\tsegment.isEnd && // only allow resizing on the final segment for an event\n\t\t\tisEventResizable(event)\n\t\t) {\n\t\t\tt.resizableDayEvent(event, eventElement, segment); // use `t` so subclasses can override\n\t\t}\n\n\t\t// attach all other handlers.\n\t\t// needs to be after, because resizableDayEvent might stopImmediatePropagation on click\n\t\teventElementHandlers(event, eventElement);\n\t}\n\n\t\n\tfunction draggableDayEvent(event, eventElement) {\n\t\tvar hoverListener = getHoverListener();\n\t\tvar dayDelta;\n\t\teventElement.draggable({\n\t\t\tdelay: 50,\n\t\t\topacity: opt('dragOpacity'),\n\t\t\trevertDuration: opt('dragRevertDuration'),\n\t\t\tstart: function(ev, ui) {\n\t\t\t\ttrigger('eventDragStart', eventElement, event, ev, ui);\n\t\t\t\thideEvents(event, eventElement);\n\t\t\t\thoverListener.start(function(cell, origCell, rowDelta, colDelta) {\n\t\t\t\t\teventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);\n\t\t\t\t\tclearOverlays();\n\t\t\t\t\tif (cell) {\n\t\t\t\t\t\tvar origDate = cellToDate(origCell);\n\t\t\t\t\t\tvar date = cellToDate(cell);\n\t\t\t\t\t\tdayDelta = dayDiff(date, origDate);\n\t\t\t\t\t\trenderDayOverlay(\n\t\t\t\t\t\t\taddDays(cloneDate(event.start), dayDelta),\n\t\t\t\t\t\t\taddDays(exclEndDay(event), dayDelta)\n\t\t\t\t\t\t);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tdayDelta = 0;\n\t\t\t\t\t}\n\t\t\t\t}, ev, 'drag');\n\t\t\t},\n\t\t\tstop: function(ev, ui) {\n\t\t\t\thoverListener.stop();\n\t\t\t\tclearOverlays();\n\t\t\t\ttrigger('eventDragStop', eventElement, event, ev, ui);\n\t\t\t\tif (dayDelta) {\n\t\t\t\t\teventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);\n\t\t\t\t}else{\n\t\t\t\t\teventElement.css('filter', ''); // clear IE opacity side-effects\n\t\t\t\t\tshowEvents(event, eventElement);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t\n\tfunction resizableDayEvent(event, element, segment) {\n\t\tvar isRTL = opt('isRTL');\n\t\tvar direction = isRTL ? 'w' : 'e';\n\t\tvar handle = element.find('.ui-resizable-' + direction); // TODO: stop using this class because we aren't using jqui for this\n\t\tvar isResizing = false;\n\t\t\n\t\t// TODO: look into using jquery-ui mouse widget for this stuff\n\t\tdisableTextSelection(element); // prevent native <a> selection for IE\n\t\telement\n\t\t\t.mousedown(function(ev) { // prevent native <a> selection for others\n\t\t\t\tev.preventDefault();\n\t\t\t})\n\t\t\t.click(function(ev) {\n\t\t\t\tif (isResizing) {\n\t\t\t\t\tev.preventDefault(); // prevent link from being visited (only method that worked in IE6)\n\t\t\t\t\tev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called\n\t\t\t\t\t                               // (eventElementHandlers needs to be bound after resizableDayEvent)\n\t\t\t\t}\n\t\t\t});\n\t\t\n\t\thandle.mousedown(function(ev) {\n\t\t\tif (ev.which != 1) {\n\t\t\t\treturn; // needs to be left mouse button\n\t\t\t}\n\t\t\tisResizing = true;\n\t\t\tvar hoverListener = getHoverListener();\n\t\t\tvar rowCnt = getRowCnt();\n\t\t\tvar colCnt = getColCnt();\n\t\t\tvar elementTop = element.css('top');\n\t\t\tvar dayDelta;\n\t\t\tvar helpers;\n\t\t\tvar eventCopy = $.extend({}, event);\n\t\t\tvar minCellOffset = dayOffsetToCellOffset( dateToDayOffset(event.start) );\n\t\t\tclearSelection();\n\t\t\t$('body')\n\t\t\t\t.css('cursor', direction + '-resize')\n\t\t\t\t.one('mouseup', mouseup);\n\t\t\ttrigger('eventResizeStart', this, event, ev);\n\t\t\thoverListener.start(function(cell, origCell) {\n\t\t\t\tif (cell) {\n\n\t\t\t\t\tvar origCellOffset = cellToCellOffset(origCell);\n\t\t\t\t\tvar cellOffset = cellToCellOffset(cell);\n\n\t\t\t\t\t// don't let resizing move earlier than start date cell\n\t\t\t\t\tcellOffset = Math.max(cellOffset, minCellOffset);\n\n\t\t\t\t\tdayDelta =\n\t\t\t\t\t\tcellOffsetToDayOffset(cellOffset) -\n\t\t\t\t\t\tcellOffsetToDayOffset(origCellOffset);\n\n\t\t\t\t\tif (dayDelta) {\n\t\t\t\t\t\teventCopy.end = addDays(eventEnd(event), dayDelta, true);\n\t\t\t\t\t\tvar oldHelpers = helpers;\n\n\t\t\t\t\t\thelpers = renderTempDayEvent(eventCopy, segment.row, elementTop);\n\t\t\t\t\t\thelpers = $(helpers); // turn array into a jQuery object\n\n\t\t\t\t\t\thelpers.find('*').css('cursor', direction + '-resize');\n\t\t\t\t\t\tif (oldHelpers) {\n\t\t\t\t\t\t\toldHelpers.remove();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thideEvents(event);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (helpers) {\n\t\t\t\t\t\t\tshowEvents(event);\n\t\t\t\t\t\t\thelpers.remove();\n\t\t\t\t\t\t\thelpers = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tclearOverlays();\n\t\t\t\t\trenderDayOverlay( // coordinate grid already rebuilt with hoverListener.start()\n\t\t\t\t\t\tevent.start,\n\t\t\t\t\t\taddDays( exclEndDay(event), dayDelta )\n\t\t\t\t\t\t// TODO: instead of calling renderDayOverlay() with dates,\n\t\t\t\t\t\t// call _renderDayOverlay (or whatever) with cell offsets.\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}, ev);\n\t\t\t\n\t\t\tfunction mouseup(ev) {\n\t\t\t\ttrigger('eventResizeStop', this, event, ev);\n\t\t\t\t$('body').css('cursor', '');\n\t\t\t\thoverListener.stop();\n\t\t\t\tclearOverlays();\n\t\t\t\tif (dayDelta) {\n\t\t\t\t\teventResize(this, event, dayDelta, 0, ev);\n\t\t\t\t\t// event redraw will clear helpers\n\t\t\t\t}\n\t\t\t\t// otherwise, the drag handler already restored the old events\n\t\t\t\t\n\t\t\t\tsetTimeout(function() { // make this happen after the element's click event\n\t\t\t\t\tisResizing = false;\n\t\t\t\t},0);\n\t\t\t}\n\t\t});\n\t}\n\t\n\n}\n\n\n\n/* Generalized Segment Utilities\n-------------------------------------------------------------------------------------------------*/\n\n\nfunction isDaySegmentCollision(segment, otherSegments) {\n\tfor (var i=0; i<otherSegments.length; i++) {\n\t\tvar otherSegment = otherSegments[i];\n\t\tif (\n\t\t\totherSegment.leftCol <= segment.rightCol &&\n\t\t\totherSegment.rightCol >= segment.leftCol\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\nfunction segmentElementEach(segments, callback) { // TODO: use in AgendaView?\n\tfor (var i=0; i<segments.length; i++) {\n\t\tvar segment = segments[i];\n\t\tvar element = segment.element;\n\t\tif (element) {\n\t\t\tcallback(segment, element, i);\n\t\t}\n\t}\n}\n\n\n// A cmp function for determining which segments should appear higher up\nfunction compareDaySegments(a, b) {\n\treturn (b.rightCol - b.leftCol) - (a.rightCol - a.leftCol) || // put wider events first\n\t\tb.event.allDay - a.event.allDay || // if tie, put all-day events first (booleans cast to 0/1)\n\t\ta.event.start - b.event.start || // if a tie, sort by event start date\n\t\t(a.event.title || '').localeCompare(b.event.title) // if a tie, sort by event title\n}\n\n\n;;\n\n//BUG: unselect needs to be triggered when events are dragged+dropped\n\nfunction SelectionManager() {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.select = select;\n\tt.unselect = unselect;\n\tt.reportSelection = reportSelection;\n\tt.daySelectionMousedown = daySelectionMousedown;\n\t\n\t\n\t// imports\n\tvar opt = t.opt;\n\tvar trigger = t.trigger;\n\tvar defaultSelectionEnd = t.defaultSelectionEnd;\n\tvar renderSelection = t.renderSelection;\n\tvar clearSelection = t.clearSelection;\n\t\n\t\n\t// locals\n\tvar selected = false;\n\n\n\n\t// unselectAuto\n\tif (opt('selectable') && opt('unselectAuto')) {\n\t\t$(document).mousedown(function(ev) {\n\t\t\tvar ignore = opt('unselectCancel');\n\t\t\tif (ignore) {\n\t\t\t\tif ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tunselect(ev);\n\t\t});\n\t}\n\t\n\n\tfunction select(startDate, endDate, allDay) {\n\t\tunselect();\n\t\tif (!endDate) {\n\t\t\tendDate = defaultSelectionEnd(startDate, allDay);\n\t\t}\n\t\trenderSelection(startDate, endDate, allDay);\n\t\treportSelection(startDate, endDate, allDay);\n\t}\n\t\n\t\n\tfunction unselect(ev) {\n\t\tif (selected) {\n\t\t\tselected = false;\n\t\t\tclearSelection();\n\t\t\ttrigger('unselect', null, ev);\n\t\t}\n\t}\n\t\n\t\n\tfunction reportSelection(startDate, endDate, allDay, ev) {\n\t\tselected = true;\n\t\ttrigger('select', null, startDate, endDate, allDay, ev);\n\t}\n\t\n\t\n\tfunction daySelectionMousedown(ev) { // not really a generic manager method, oh well\n\t\tvar cellToDate = t.cellToDate;\n\t\tvar getIsCellAllDay = t.getIsCellAllDay;\n\t\tvar hoverListener = t.getHoverListener();\n\t\tvar reportDayClick = t.reportDayClick; // this is hacky and sort of weird\n\t\tif (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button\n\t\t\tunselect(ev);\n\t\t\tvar _mousedownElement = this;\n\t\t\tvar dates;\n\t\t\thoverListener.start(function(cell, origCell) { // TODO: maybe put cellToDate/getIsCellAllDay info in cell\n\t\t\t\tclearSelection();\n\t\t\t\tif (cell && getIsCellAllDay(cell)) {\n\t\t\t\t\tdates = [ cellToDate(origCell), cellToDate(cell) ].sort(dateCompare);\n\t\t\t\t\trenderSelection(dates[0], dates[1], true);\n\t\t\t\t}else{\n\t\t\t\t\tdates = null;\n\t\t\t\t}\n\t\t\t}, ev);\n\t\t\t$(document).one('mouseup', function(ev) {\n\t\t\t\thoverListener.stop();\n\t\t\t\tif (dates) {\n\t\t\t\t\tif (+dates[0] == +dates[1]) {\n\t\t\t\t\t\treportDayClick(dates[0], true, ev);\n\t\t\t\t\t}\n\t\t\t\t\treportSelection(dates[0], dates[1], true, ev);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n}\n\n;;\n \nfunction OverlayManager() {\n\tvar t = this;\n\t\n\t\n\t// exports\n\tt.renderOverlay = renderOverlay;\n\tt.clearOverlays = clearOverlays;\n\t\n\t\n\t// locals\n\tvar usedOverlays = [];\n\tvar unusedOverlays = [];\n\t\n\t\n\tfunction renderOverlay(rect, parent) {\n\t\tvar e = unusedOverlays.shift();\n\t\tif (!e) {\n\t\t\te = $(\"<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>\");\n\t\t}\n\t\tif (e[0].parentNode != parent[0]) {\n\t\t\te.appendTo(parent);\n\t\t}\n\t\tusedOverlays.push(e.css(rect).show());\n\t\treturn e;\n\t}\n\t\n\n\tfunction clearOverlays() {\n\t\tvar e;\n\t\twhile (e = usedOverlays.shift()) {\n\t\t\tunusedOverlays.push(e.hide().unbind());\n\t\t}\n\t}\n\n\n}\n\n;;\n\nfunction CoordinateGrid(buildFunc) {\n\n\tvar t = this;\n\tvar rows;\n\tvar cols;\n\t\n\t\n\tt.build = function() {\n\t\trows = [];\n\t\tcols = [];\n\t\tbuildFunc(rows, cols);\n\t};\n\t\n\t\n\tt.cell = function(x, y) {\n\t\tvar rowCnt = rows.length;\n\t\tvar colCnt = cols.length;\n\t\tvar i, r=-1, c=-1;\n\t\tfor (i=0; i<rowCnt; i++) {\n\t\t\tif (y >= rows[i][0] && y < rows[i][1]) {\n\t\t\t\tr = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tfor (i=0; i<colCnt; i++) {\n\t\t\tif (x >= cols[i][0] && x < cols[i][1]) {\n\t\t\t\tc = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn (r>=0 && c>=0) ? { row:r, col:c } : null;\n\t};\n\t\n\t\n\tt.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive\n\t\tvar origin = originElement.offset();\n\t\treturn {\n\t\t\ttop: rows[row0][0] - origin.top,\n\t\t\tleft: cols[col0][0] - origin.left,\n\t\t\twidth: cols[col1][1] - cols[col0][0],\n\t\t\theight: rows[row1][1] - rows[row0][0]\n\t\t};\n\t};\n\n}\n\n;;\n\nfunction HoverListener(coordinateGrid) {\n\n\n\tvar t = this;\n\tvar bindType;\n\tvar change;\n\tvar firstCell;\n\tvar cell;\n\t\n\t\n\tt.start = function(_change, ev, _bindType) {\n\t\tchange = _change;\n\t\tfirstCell = cell = null;\n\t\tcoordinateGrid.build();\n\t\tmouse(ev);\n\t\tbindType = _bindType || 'mousemove';\n\t\t$(document).bind(bindType, mouse);\n\t};\n\t\n\t\n\tfunction mouse(ev) {\n\t\t_fixUIEvent(ev); // see below\n\t\tvar newCell = coordinateGrid.cell(ev.pageX, ev.pageY);\n\t\tif (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {\n\t\t\tif (newCell) {\n\t\t\t\tif (!firstCell) {\n\t\t\t\t\tfirstCell = newCell;\n\t\t\t\t}\n\t\t\t\tchange(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);\n\t\t\t}else{\n\t\t\t\tchange(newCell, firstCell);\n\t\t\t}\n\t\t\tcell = newCell;\n\t\t}\n\t}\n\t\n\t\n\tt.stop = function() {\n\t\t$(document).unbind(bindType, mouse);\n\t\treturn cell;\n\t};\n\t\n\t\n}\n\n\n\n// this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1)\n// upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem\n// but keep this in here for 1.8.16 users\n// and maybe remove it down the line\n\nfunction _fixUIEvent(event) { // for issue 1168\n\tif (event.pageX === undefined) {\n\t\tevent.pageX = event.originalEvent.pageX;\n\t\tevent.pageY = event.originalEvent.pageY;\n\t}\n}\n;;\n\nfunction HorizontalPositionCache(getElement) {\n\n\tvar t = this,\n\t\telements = {},\n\t\tlefts = {},\n\t\trights = {};\n\t\t\n\tfunction e(i) {\n\t\treturn elements[i] = elements[i] || getElement(i);\n\t}\n\t\n\tt.left = function(i) {\n\t\treturn lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];\n\t};\n\t\n\tt.right = function(i) {\n\t\treturn rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];\n\t};\n\t\n\tt.clear = function() {\n\t\telements = {};\n\t\tlefts = {};\n\t\trights = {};\n\t};\n\t\n}\n\n;;\n\n})(jQuery);"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.print.css",
    "content": "/*!\n * FullCalendar v1.6.4 Print Stylesheet\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n\n/*\n * Include this stylesheet on your page to get a more printer-friendly calendar.\n * When including this stylesheet, use the media='print' attribute of the <link> tag.\n * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.\n */\n \n \n /* Events\n-----------------------------------------------------*/\n \n.fc-event {\n\tbackground: #fff !important;\n\tcolor: #000 !important;\n\t}\n\t\n/* for vertical events */\n\t\n.fc-event-bg {\n\tdisplay: none !important;\n\t}\n\t\n.fc-event .ui-resizable-handle {\n\tdisplay: none !important;\n\t}\n\t\n\t\n"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/gcal.js",
    "content": "/*!\n * FullCalendar v1.6.4 Google Calendar Plugin\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n \n(function($) {\n\n\nvar fc = $.fullCalendar;\nvar formatDate = fc.formatDate;\nvar parseISO8601 = fc.parseISO8601;\nvar addDays = fc.addDays;\nvar applyAll = fc.applyAll;\n\n\nfc.sourceNormalizers.push(function(sourceOptions) {\n\tif (sourceOptions.dataType == 'gcal' ||\n\t\tsourceOptions.dataType === undefined &&\n\t\t(sourceOptions.url || '').match(/^(http|https):\\/\\/www.google.com\\/calendar\\/feeds\\//)) {\n\t\t\tsourceOptions.dataType = 'gcal';\n\t\t\tif (sourceOptions.editable === undefined) {\n\t\t\t\tsourceOptions.editable = false;\n\t\t\t}\n\t\t}\n});\n\n\nfc.sourceFetchers.push(function(sourceOptions, start, end) {\n\tif (sourceOptions.dataType == 'gcal') {\n\t\treturn transformOptions(sourceOptions, start, end);\n\t}\n});\n\n\nfunction transformOptions(sourceOptions, start, end) {\n\n\tvar success = sourceOptions.success;\n\tvar data = $.extend({}, sourceOptions.data || {}, {\n\t\t'start-min': formatDate(start, 'u'),\n\t\t'start-max': formatDate(end, 'u'),\n\t\t'singleevents': true,\n\t\t'max-results': 9999\n\t});\n\t\n\tvar ctz = sourceOptions.currentTimezone;\n\tif (ctz) {\n\t\tdata.ctz = ctz = ctz.replace(' ', '_');\n\t}\n\n\treturn $.extend({}, sourceOptions, {\n\t\turl: sourceOptions.url.replace(/\\/basic$/, '/full') + '?alt=json-in-script&callback=?',\n\t\tdataType: 'jsonp',\n\t\tdata: data,\n\t\tstartParam: false,\n\t\tendParam: false,\n\t\tsuccess: function(data) {\n\t\t\tvar events = [];\n\t\t\tif (data.feed.entry) {\n\t\t\t\t$.each(data.feed.entry, function(i, entry) {\n\t\t\t\t\tvar startStr = entry['gd$when'][0]['startTime'];\n\t\t\t\t\tvar start = parseISO8601(startStr, true);\n\t\t\t\t\tvar end = parseISO8601(entry['gd$when'][0]['endTime'], true);\n\t\t\t\t\tvar allDay = startStr.indexOf('T') == -1;\n\t\t\t\t\tvar url;\n\t\t\t\t\t$.each(entry.link, function(i, link) {\n\t\t\t\t\t\tif (link.type == 'text/html') {\n\t\t\t\t\t\t\turl = link.href;\n\t\t\t\t\t\t\tif (ctz) {\n\t\t\t\t\t\t\t\turl += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (allDay) {\n\t\t\t\t\t\taddDays(end, -1); // make inclusive\n\t\t\t\t\t}\n\t\t\t\t\tevents.push({\n\t\t\t\t\t\tid: entry['gCal$uid']['value'],\n\t\t\t\t\t\ttitle: entry['title']['$t'],\n\t\t\t\t\t\turl: url,\n\t\t\t\t\t\tstart: start,\n\t\t\t\t\t\tend: end,\n\t\t\t\t\t\tallDay: allDay,\n\t\t\t\t\t\tlocation: entry['gd$where'][0]['valueString'],\n\t\t\t\t\t\tdescription: entry['content']['$t']\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t\tvar args = [events].concat(Array.prototype.slice.call(arguments, 1));\n\t\t\tvar res = applyAll(success, this, args);\n\t\t\tif ($.isArray(res)) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t\treturn events;\n\t\t}\n\t});\n\t\n}\n\n\n// legacy\nfc.gcalFeed = function(url, sourceOptions) {\n\treturn $.extend({}, sourceOptions, { url: url, dataType: 'gcal' });\n};\n\n\n})(jQuery);\n"
  },
  {
    "path": "input-scripts/fullcalendar/lib/jquery-2.1.0.js",
    "content": "/*!\n * jQuery JavaScript Library v2.1.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-01-23T21:10Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper window is present,\n\t\t// execute the factory and get jQuery\n\t\t// For environments that do not inherently posses a window with a document\n\t\t// (such as Node.js), expose a jQuery-making factory as module.exports\n\t\t// This accentuates the need for the creation of a real window\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Can't do this because several apps including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n// Support: Firefox 18+\n//\n\nvar arr = [];\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar trim = \"\".trim;\n\nvar support = {};\n\n\n\nvar\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\n\tversion = \"2.1.0\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num != null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return just the object\n\t\t\tslice.call( this );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray,\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\treturn obj - parseFloat( obj ) >= 0;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Not plain objects:\n\t\t// - Any object or value whose internal [[Class]] property is not \"[object Object]\"\n\t\t// - DOM nodes\n\t\t// - window\n\t\tif ( jQuery.type( obj ) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Support: Firefox <20\n\t\t// The try/catch suppresses exceptions thrown when attempting to access\n\t\t// the \"constructor\" property of certain host objects, ie. |window.location|\n\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=814622\n\t\ttry {\n\t\t\tif ( obj.constructor &&\n\t\t\t\t\t!hasOwn.call( obj.constructor.prototype, \"isPrototypeOf\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the function hasn't returned already, we're confident that\n\t\t// |obj| is a plain object, created by {} or constructed with new Object\n\t\treturn true;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\t\t// Support: Android < 4.0, iOS < 6 (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tvar script,\n\t\t\tindirect = eval;\n\n\t\tcode = jQuery.trim( code );\n\n\t\tif ( code ) {\n\t\t\t// If the code includes a valid, prologue position\n\t\t\t// strict mode pragma, execute code by injecting a\n\t\t\t// script tag into the document.\n\t\t\tif ( code.indexOf(\"use strict\") === 1 ) {\n\t\t\t\tscript = document.createElement(\"script\");\n\t\t\t\tscript.text = code;\n\t\t\t\tdocument.head.appendChild( script ).parentNode.removeChild( script );\n\t\t\t} else {\n\t\t\t// Otherwise, avoid the DOM node creation, insertion\n\t\t\t// and removal by using an indirect global eval\n\t\t\t\tindirect( code );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\ttrim: function( text ) {\n\t\treturn text == null ? \"\" : trim.call( text );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\tvar length = obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v1.10.16\n * http://sizzlejs.com/\n *\n * Copyright 2013 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-01-13\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\tcompile,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + -(new Date()),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tstrundefined = typeof undefined,\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf if we can't use a native one\n\tindexOf = arr.indexOf || function( elem ) {\n\t\tvar i = 0,\n\t\t\tlen = this.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( this[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")\" + whitespace +\n\t\t\"*(?:([*^$|!~]?=)\" + whitespace + \"*(?:(['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|(\" + identifier + \")|)|)\" + whitespace + \"*\\\\]\",\n\n\t// Prefer arguments quoted,\n\t//   then not containing pseudos/brackets,\n\t//   then attribute selectors/non-parenthetical expressions,\n\t//   then anything else\n\t// These preferences are here to reduce the number of selectors\n\t//   needing tokenize in the PSEUDO preFilter\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\(((['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes.replace( 3, 8 ) + \")*)|.*)\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tif ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( documentIsHTML && !seed ) {\n\n\t\t// Shortcuts\n\t\tif ( (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document (jQuery #6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\t\t\tnid = old = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType === 9 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = attrs.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== strundefined && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc,\n\t\tparent = doc.defaultView;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\n\t// Support tests\n\tdocumentIsHTML = !isXML( doc );\n\n\t// Support: IE>8\n\t// If iframe document is assigned to \"document\" variable and if iframe has been reloaded,\n\t// IE will throw \"permission denied\" error when accessing \"document\" variable, see jQuery #13936\n\t// IE6-8 do not support the defaultView property so parent will be undefined\n\tif ( parent && parent !== parent.top ) {\n\t\t// IE11 does not have attachEvent, so all must suffer\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", function() {\n\t\t\t\tsetDocument();\n\t\t\t}, false );\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", function() {\n\t\t\t\tsetDocument();\n\t\t\t});\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Check if getElementsByClassName can be trusted\n\tsupport.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {\n\t\tdiv.innerHTML = \"<div class='a'></div><div class='a i'></div>\";\n\n\t\t// Support: Safari<4\n\t\t// Catch class over-caching\n\t\tdiv.firstChild.className = \"i\";\n\t\t// Support: Opera<10\n\t\t// Catch gEBCN failure to find non-leading classes\n\t\treturn div.getElementsByClassName(\"i\").length === 2;\n\t});\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !doc.getElementsByName || !doc.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [m] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== strundefined ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\t\t\t}\n\t\t} :\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdiv.innerHTML = \"<select t=''><option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 10-12\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\tif ( div.querySelectorAll(\"[t^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = doc.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn doc;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch(e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [elem] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[5] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] && match[4] !== undefined ) {\n\t\t\t\tmatch[2] = match[4];\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf.call( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (oldCache = outerCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\treturn ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Keep `i` a string if there are no elements so `matchedCount` will be \"00\" below\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !group ) {\n\t\t\tgroup = tokenize( selector );\n\t\t}\n\t\ti = group.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( group[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\t}\n\treturn cached;\n};\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tmatch = tokenize( selector );\n\n\tif ( !seed ) {\n\t\t// Try to minimize operations if there is only one group\n\t\tif ( match.length === 1 ) {\n\n\t\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t\ttokens = match[0] = match[0].slice( 0 );\n\t\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\t\tif ( !context ) {\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t\t}\n\n\t\t\t// Fetch a seed set for right-to-left matching\n\t\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\ttoken = tokens[i];\n\n\t\t\t\t// Abort if we hit a combinator\n\t\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\t\tif ( (seed = find(\n\t\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t\t)) ) {\n\n\t\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\tcompile( selector, match )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\trsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome<14\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = (/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/);\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t});\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t});\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) >= 0 ) !== not;\n\t});\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t}));\n};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tlen = this.length,\n\t\t\tret = [],\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}) );\n\t\t}\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], false) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], true) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n});\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[0] === \"<\" && selector[ selector.length - 1 ] === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\n\t\t\t\t\t// scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn typeof rootjQuery.ready !== \"undefined\" ?\n\t\t\t\trootjQuery.ready( selector ) :\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\t// methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.extend({\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\ttruncate = until !== undefined;\n\n\t\twhile ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmatched.push( elem );\n\t\t\t}\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar matched = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tmatched.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn matched;\n\t}\n});\n\njQuery.fn.extend({\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && (pos ?\n\t\t\t\t\tpos.index(cur) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector(cur, selectors)) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.unique(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\nfunction sibling( cur, dir ) {\n\twhile ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn elem.contentDocument || jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.unique( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n});\nvar rnotwhite = (/\\S+/g);\n\n\n\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// Flag to know if list is currently firing\n\t\tfiring,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\tfiringLength = 0;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend({\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.trigger ) {\n\t\t\tjQuery( document ).trigger(\"ready\").off(\"ready\");\n\t\t}\n\t}\n});\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\twindow.removeEventListener( \"load\", completed, false );\n\tjQuery.ready();\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// we once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t} else {\n\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed, false );\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Kick off the DOM ready check even if the user does not\njQuery.ready.promise();\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlen ? fn( elems[0], key ) : emptyGet;\n};\n\n\n/**\n * Determines whether an object can have data\n */\njQuery.acceptData = function( owner ) {\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\t/* jshint -W018 */\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\nfunction Data() {\n\t// Support: Android < 4,\n\t// Old WebKit does not have Object.preventExtensions/freeze method,\n\t// return new empty object instead with no [[set]] accessor\n\tObject.defineProperty( this.cache = {}, 0, {\n\t\tget: function() {\n\t\t\treturn {};\n\t\t}\n\t});\n\n\tthis.expando = jQuery.expando + Math.random();\n}\n\nData.uid = 1;\nData.accepts = jQuery.acceptData;\n\nData.prototype = {\n\tkey: function( owner ) {\n\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t// but we should not, see #8335.\n\t\t// Always return the key for a frozen object.\n\t\tif ( !Data.accepts( owner ) ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar descriptor = {},\n\t\t\t// Check if the owner object already has a cache key\n\t\t\tunlock = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !unlock ) {\n\t\t\tunlock = Data.uid++;\n\n\t\t\t// Secure it in a non-enumerable, non-writable property\n\t\t\ttry {\n\t\t\t\tdescriptor[ this.expando ] = { value: unlock };\n\t\t\t\tObject.defineProperties( owner, descriptor );\n\n\t\t\t// Support: Android < 4\n\t\t\t// Fallback to a less secure definition\n\t\t\t} catch ( e ) {\n\t\t\t\tdescriptor[ this.expando ] = unlock;\n\t\t\t\tjQuery.extend( owner, descriptor );\n\t\t\t}\n\t\t}\n\n\t\t// Ensure the cache object\n\t\tif ( !this.cache[ unlock ] ) {\n\t\t\tthis.cache[ unlock ] = {};\n\t\t}\n\n\t\treturn unlock;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\t// There may be an unlock assigned to this node,\n\t\t\t// if there is no entry for this \"owner\", create one inline\n\t\t\t// and set the unlock as though an owner entry had always existed\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\t// Handle: [ owner, key, value ] args\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ data ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\t\t\t// Fresh assignments by object are shallow copied\n\t\t\tif ( jQuery.isEmptyObject( cache ) ) {\n\t\t\t\tjQuery.extend( this.cache[ unlock ], data );\n\t\t\t// Otherwise, copy the properties one-by-one to the cache object\n\t\t\t} else {\n\t\t\t\tfor ( prop in data ) {\n\t\t\t\t\tcache[ prop ] = data[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\t// Either a valid cache is found, or will be created.\n\t\t// New caches will be created and the unlock returned,\n\t\t// allowing direct access to the newly created\n\t\t// empty data object. A valid owner object must be provided.\n\t\tvar cache = this.cache[ this.key( owner ) ];\n\n\t\treturn key === undefined ?\n\t\t\tcache : cache[ key ];\n\t},\n\taccess: function( owner, key, value ) {\n\t\tvar stored;\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t((key && typeof key === \"string\") && value === undefined) ) {\n\n\t\t\tstored = this.get( owner, key );\n\n\t\t\treturn stored !== undefined ?\n\t\t\t\tstored : this.get( owner, jQuery.camelCase(key) );\n\t\t}\n\n\t\t// [*]When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i, name, camel,\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\tif ( key === undefined ) {\n\t\t\tthis.cache[ unlock ] = {};\n\n\t\t} else {\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( jQuery.isArray( key ) ) {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = key.concat( key.map( jQuery.camelCase ) );\n\t\t\t} else {\n\t\t\t\tcamel = jQuery.camelCase( key );\n\t\t\t\t// Try the string as a key before any manipulation\n\t\t\t\tif ( key in cache ) {\n\t\t\t\t\tname = [ key, camel ];\n\t\t\t\t} else {\n\t\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\t\tname = camel;\n\t\t\t\t\tname = name in cache ?\n\t\t\t\t\t\t[ name ] : ( name.match( rnotwhite ) || [] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = name.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ name[ i ] ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\treturn !jQuery.isEmptyObject(\n\t\t\tthis.cache[ owner[ this.expando ] ] || {}\n\t\t);\n\t},\n\tdiscard: function( owner ) {\n\t\tif ( owner[ this.expando ] ) {\n\t\t\tdelete this.cache[ owner[ this.expando ] ];\n\t\t}\n\t}\n};\nvar data_priv = new Data();\n\nvar data_user = new Data();\n\n\n\n/*\n\tImplementation Summary\n\n\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n\t2. Improve the module's maintainability by reducing the storage\n\t\tpaths to a single mechanism.\n\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n*/\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdata_user.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend({\n\thasData: function( elem ) {\n\t\treturn data_user.hasData( elem ) || data_priv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn data_user.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdata_user.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to data_priv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn data_priv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdata_priv.remove( elem, name );\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = data_user.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !data_priv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tname = attrs[ i ].name;\n\n\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice(5) );\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdata_priv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tdata_user.set( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data,\n\t\t\t\tcamelKey = jQuery.camelCase( key );\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key as-is\n\t\t\t\tdata = data_user.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key camelized\n\t\t\t\tdata = data_user.get( elem, camelKey );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, camelKey, undefined );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each(function() {\n\t\t\t\t// First, attempt to store a copy or reference of any\n\t\t\t\t// data that might've been store with a camelCased key.\n\t\t\t\tvar data = data_user.get( this, camelKey );\n\n\t\t\t\t// For HTML5 data-* attribute interop, we have to\n\t\t\t\t// store property names with dashes in a camelCase form.\n\t\t\t\t// This might not apply to all properties...*\n\t\t\t\tdata_user.set( this, camelKey, value );\n\n\t\t\t\t// *... In the case of properties that might _actually_\n\t\t\t\t// have dashes, we need to also store a copy of that\n\t\t\t\t// unchanged property.\n\t\t\t\tif ( key.indexOf(\"-\") !== -1 && data !== undefined ) {\n\t\t\t\t\tdata_user.set( this, key, value );\n\t\t\t\t}\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tdata_user.remove( this, key );\n\t\t});\n\t}\n});\n\n\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = data_priv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray( data ) ) {\n\t\t\t\t\tqueue = data_priv.access( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// not intended for public consumption - generates a queueHooks object, or returns the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn data_priv.get( elem, key ) || data_priv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tdata_priv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = data_priv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar pnum = (/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/).source;\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n\t};\n\nvar rcheckableType = (/^(?:checkbox|radio)$/i);\n\n\n\n(function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) );\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tdiv.innerHTML = \"<input type='radio' checked='checked' name='t'/>\";\n\n\t// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3\n\t// old WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\t// Support: IE9-IE11+\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n})();\nvar strundefined = typeof undefined;\n\n\n\nsupport.focusinBubbles = \"onfocusin\" in window;\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.hasData( elem ) && data_priv.get( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdelete elemData.handle;\n\t\t\tdata_priv.remove( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( data_priv.get( cur, \"events\" ) || {} )[ event.type ] && data_priv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && jQuery.acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&\n\t\t\t\tjQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( data_priv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or\n\t\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.disabled !== true || event.type !== \"click\" ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: Cordova 2.5 (WebKit) (#13255)\n\t\t// All events should have a target; Cordova deviceready doesn't\n\t\tif ( !event.target ) {\n\t\t\tevent.target = document;\n\t\t}\n\n\t\t// Support: Safari 6.0+, Chrome < 28\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle, false );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\t// Support: Android < 4.0\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\t\t\t\tsrc.getPreventDefault && src.getPreventDefault() ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = 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\njQuery.Event.prototype = {\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && e.preventDefault ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// Support: Chrome 15+\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// Create \"bubbling\" focus and blur events\n// Support: Firefox, Chrome, Safari\nif ( !support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdata_priv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdata_priv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdata_priv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar origFn, type;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n});\n\n\nvar\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\n\t\t// Support: IE 9\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t_default: [ 0, \"\", \"\" ]\n\t};\n\n// Support: IE 9\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: 1.x compatibility\n// Manipulating tables requires a tbody\nfunction manipulationTarget( elem, content ) {\n\treturn jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ?\n\n\t\telem.getElementsByTagName(\"tbody\")[0] ||\n\t\t\telem.appendChild( elem.ownerDocument.createElement(\"tbody\") ) :\n\t\telem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = (elem.getAttribute(\"type\") !== null) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdata_priv.set(\n\t\t\telems[ i ], \"globalEval\", !refElements || data_priv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( data_priv.hasData( src ) ) {\n\t\tpdataOld = data_priv.access( src );\n\t\tpdataCur = data_priv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( data_user.hasData( src ) ) {\n\t\tudataOld = data_user.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdata_user.set( dest, udataCur );\n\t}\n}\n\nfunction getAll( context, tag ) {\n\tvar ret = context.getElementsByTagName ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\tcontext.querySelectorAll ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\t[];\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], ret ) :\n\t\tret;\n}\n\n// Support: IE >= 9\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Support: IE >= 9\n\t\t// Fix Cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar elem, tmp, tag, wrap, contains, j,\n\t\t\tfragment = context.createDocumentFragment(),\n\t\t\tnodes = [],\n\t\t\ti = 0,\n\t\t\tl = elems.length;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\t// Support: QtWebKit\n\t\t\t\t\t// jQuery.merge because push.apply(_, arraylike) throws\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\t\ttmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[ 2 ];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[ 0 ];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: QtWebKit\n\t\t\t\t\t// jQuery.merge because push.apply(_, arraylike) throws\n\t\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Remember the top-level container\n\t\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t\t// Fixes #12346\n\t\t\t\t\t// Support: Webkit, IE\n\t\t\t\t\ttmp.textContent = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Remove wrapper from fragment\n\t\tfragment.textContent = \"\";\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn fragment;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, events, type, key, j,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[ i ]) !== undefined; i++ ) {\n\t\t\tif ( jQuery.acceptData( elem ) ) {\n\t\t\t\tkey = elem[ data_priv.expando ];\n\n\t\t\t\tif ( key && (data = data_priv.cache[ key ]) ) {\n\t\t\t\t\tevents = Object.keys( data.events || {} );\n\t\t\t\t\tif ( events.length ) {\n\t\t\t\t\t\tfor ( j = 0; (type = events[j]) !== undefined; j++ ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( data_priv.cache[ key ] ) {\n\t\t\t\t\t\t// Discard any remaining `private` data\n\t\t\t\t\t\tdelete data_priv.cache[ key ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Discard any remaining `user` data\n\t\t\tdelete data_user.cache[ elem[ data_user.expando ] ];\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each(function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\tremove: function( selector, keepData /* Internal Use Only */ ) {\n\t\tvar elem,\n\t\t\telems = selector ? jQuery.filter( selector, this ) : this,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t}\n\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t}\n\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map(function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar arg = arguments[ 0 ];\n\n\t\t// Make the changes, replacing each context element with the new content\n\t\tthis.domManip( arguments, function( elem ) {\n\t\t\targ = this.parentNode;\n\n\t\t\tjQuery.cleanData( getAll( this ) );\n\n\t\t\tif ( arg ) {\n\t\t\t\targ.replaceChild( elem, this );\n\t\t\t}\n\t\t});\n\n\t\t// Force removal if there was no new content (e.g., from empty arguments)\n\t\treturn arg && (arg.length || arg.nodeType) ? this : this.remove();\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = concat.apply( [], args );\n\n\t\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[ 0 ],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction ||\n\t\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\t// Support: QtWebKit\n\t\t\t\t\t\t\t// jQuery.merge because push.apply(_, arraylike) throws\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call( this[ i ], node, i );\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!data_priv.access( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( node.textContent.replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: QtWebKit\n\t\t\t// .get() because push.apply(_, arraylike) throws\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\n\nvar iframe,\n\telemdisplay = {};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\t// getDefaultComputedStyle might be reliably used only on attached element\n\t\tdisplay = window.getDefaultComputedStyle ?\n\n\t\t\t// Use of this method is a temporary fix (more like optmization) until something better comes along,\n\t\t\t// since it was removed from specification and supported only in FF\n\t\t\twindow.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = (iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" )).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = iframe[ 0 ].contentDocument;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\nvar rmargin = (/^margin/);\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\t\treturn elem.ownerDocument.defaultView.getComputedStyle( elem, null );\n\t};\n\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// Support: IE9\n\t// getPropertyValue is only needed for .css('filter') in IE9, see #12537\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\t}\n\n\tif ( computed ) {\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// Support: iOS < 6\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\t\t// Support: IE\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\t\t\t\t// Hook not needed (or it's not possible to use it due to missing dependency),\n\t\t\t\t// remove it.\n\t\t\t\t// Since there are no other hooks for marginRight, remove the whole object.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\n\t\t\treturn (this.get = hookFn).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\n(function() {\n\tvar pixelPositionVal, boxSizingReliableVal,\n\t\t// Support: Firefox, Android 2.3 (Prefixed box-sizing versions).\n\t\tdivReset = \"padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;\" +\n\t\t\t\"-moz-box-sizing:content-box;box-sizing:content-box\",\n\t\tdocElem = document.documentElement,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px;\" +\n\t\t\"margin-top:1px\";\n\tcontainer.appendChild( div );\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computePixelPositionAndBoxSizingReliable() {\n\t\t// Support: Firefox, Android 2.3 (Prefixed box-sizing versions).\n\t\tdiv.style.cssText = \"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;\" +\n\t\t\t\"box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;\" +\n\t\t\t\"position:absolute;top:1%\";\n\t\tdocElem.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div, null );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\tdocElem.removeChild( container );\n\t}\n\n\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\tif ( window.getComputedStyle ) {\n\t\tjQuery.extend(support, {\n\t\t\tpixelPosition: function() {\n\t\t\t\t// This test is executed only once but we still do memoizing\n\t\t\t\t// since we can use the boxSizingReliable pre-computing.\n\t\t\t\t// No need to check if the test was already performed, though.\n\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\treturn pixelPositionVal;\n\t\t\t},\n\t\t\tboxSizingReliable: function() {\n\t\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\t}\n\t\t\t\treturn boxSizingReliableVal;\n\t\t\t},\n\t\t\treliableMarginRight: function() {\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t// This support function is only executed once so no memoizing is needed.\n\t\t\t\tvar ret,\n\t\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\t\t\t\tmarginDiv.style.cssText = div.style.cssText = divReset;\n\t\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\t\tdiv.style.width = \"1px\";\n\t\t\t\tdocElem.appendChild( container );\n\n\t\t\t\tret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );\n\n\t\t\t\tdocElem.removeChild( container );\n\n\t\t\t\t// Clean up the div for other support tests.\n\t\t\t\tdiv.innerHTML = \"\";\n\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\njQuery.swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar\n\t// swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trnumsplit = new RegExp( \"^(\" + pnum + \")(.*)$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + pnum + \")\", \"i\" ),\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: 0,\n\t\tfontWeight: 400\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n// return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// check for vendor prefixed names\n\tvar capName = name[0].toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// at this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// at this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// at this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// we need the check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox &&\n\t\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = data_priv.get( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = data_priv.access( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\n\t\t\tif ( !values[ index ] ) {\n\t\t\t\thidden = isHidden( elem );\n\n\t\t\t\tif ( display && display !== \"none\" || !hidden ) {\n\t\t\t\t\tdata_priv.set( elem, \"olddisplay\", hidden ? display : jQuery.css(elem, \"display\") );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.extend({\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t// normalize float css property\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set. See: #7116\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// Fixes #8908, it can be done more correctly by specifying setters in cssHooks,\n\t\t\t// but it would mean to define eight (for every problematic property) identical functions\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {\n\t\t\t\t// Support: Chrome, Safari\n\t\t\t\t// Setting style to blank string required to delete \"style: x !important;\"\n\t\t\t\tstyle[ name ] = \"\";\n\t\t\t\tstyle[ name ] = value;\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t//convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Return, converting to number if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n});\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\t\t\t\t// certain elements can have dimension info if we invisibly show them\n\t\t\t\t// however, it must have a current display style that would benefit from this\n\t\t\t\treturn elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, \"display\" ) ) ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\n// Support: Android 2.3\njQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails\n\t\t\t// so, simple values such as \"10px\" are parsed to Float.\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// use step hook for back compat - use cssHook if its there - use .style if its\n\t\t\t// available and use plain properties where available\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE9\n// Panic based approach to setting things on disconnected nodes\n\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t}\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\tunit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t\t\t// Starting value computation is required for potential unit mismatches\n\t\t\t\tstart = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +target ) &&\n\t\t\t\t\trfxnum.exec( jQuery.css( tween.elem, prop ) ),\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( start && start[ 3 ] !== unit ) {\n\t\t\t\t// Trust units reported by jQuery.css\n\t\t\t\tunit = unit || start[ 3 ];\n\n\t\t\t\t// Make sure we update the tween properties later on\n\t\t\t\tparts = parts || [];\n\n\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\tstart = +target || 1;\n\n\t\t\t\tdo {\n\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*\n\t\t\t\t\t// Use a string for doubling factor so we don't accidentally see scale as unchanged below\n\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t// Adjust and apply\n\t\t\t\t\tstart = start / scale;\n\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t\t\t// And breaking the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t}\n\n\t\t\t// Update tween properties\n\t\t\tif ( parts ) {\n\t\t\t\tstart = tween.start = +start || +target || 0;\n\t\t\t\ttween.unit = unit;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[ 1 ] ?\n\t\t\t\t\tstart + ( parts[ 1 ] + 1 ) * parts[ 2 ] :\n\t\t\t\t\t+parts[ 2 ];\n\t\t\t}\n\n\t\t\treturn tween;\n\t\t} ]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// if we include width, step value is 1 to do all cssExpand values,\n\t// if we don't include width, step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( (tween = collection[ index ].call( animation, prop, value )) ) {\n\n\t\t\t// we're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = data_priv.get( elem, \"fxshow\" );\n\n\t// handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// doing this makes sure that the complete handler will be called\n\t\t\t// before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE9-10 do not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t// Get default display if display is currently \"none\"\n\t\tif ( display === \"none\" ) {\n\t\t\tdisplay = defaultDisplay( elem.nodeName );\n\t\t}\n\t\tif ( display === \"inline\" &&\n\t\t\t\tjQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\tstyle.display = \"inline-block\";\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always(function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t});\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = data_priv.access( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\n\t\t\tdata_priv.remove( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// not quite $.extend, this wont overwrite keys already present.\n\t\t\t// also - reusing 'index' from above because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// if we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// resolve when we played the last frame\n\t\t\t\t// otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || data_priv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = data_priv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// start the next in the queue if the last step wasn't forced\n\t\t\t// timers currently will call their complete callbacks, which will dequeue\n\t\t\t// but only if they were gotoEnd\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = data_priv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\tclearTimeout( timeout );\n\t\t};\n\t});\n};\n\n\n(function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: iOS 5.1, Android 4.x, Android 2.3\n\t// Check the default checkbox/radio value (\"\" on old WebKit; \"on\" elsewhere)\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Must access the parent to make an option select properly\n\t// Support: IE9, IE10\n\tsupport.optSelected = opt.selected;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Check if an input maintains its value after becoming a radio\n\t// Support: IE9, IE10\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n})();\n\n\nvar nodeHook, boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tattr: function( elem, name, value ) {\n\t\tvar hooks, ret,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\n\t\t\t} else if ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\t\t\tret = jQuery.find.attr( elem, name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret == null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tjQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to default in case type is set after value during creation\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle;\n\t\tif ( !isXML ) {\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ name ];\n\t\t\tattrHandle[ name ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tname.toLowerCase() :\n\t\t\t\tnull;\n\t\t\tattrHandle[ name ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n});\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i;\n\njQuery.fn.extend({\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\treturn hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?\n\t\t\t\tret :\n\t\t\t\t( elem[ name ] = value );\n\n\t\t} else {\n\t\t\treturn hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ?\n\t\t\t\tret :\n\t\t\t\telem[ name ];\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.hasAttribute( \"tabindex\" ) || rfocusable.test( elem.nodeName ) || elem.href ?\n\t\t\t\t\telem.tabIndex :\n\t\t\t\t\t-1;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Support: IE9+\n// Selectedness for an option in an optgroup can be inaccurate\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t};\n}\n\njQuery.each([\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n});\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\njQuery.fn.extend({\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === strundefined || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tdata_priv.set( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed \"false\",\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tthis.className = this.className || value === false ? \"\" : data_priv.get( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n});\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend({\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// IE6-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( support.optDisabled ? !option.disabled : option.getAttribute( \"disabled\" ) === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\t\t\t\t\tif ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Radios and checkboxes getter/setter\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\t// Support: Webkit\n\t\t\t// \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t};\n\t}\n});\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n});\n\njQuery.fn.extend({\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t}\n});\n\n\nvar nonce = jQuery.now();\n\nvar rquery = (/\\?/);\n\n\n\n// Support: Android 2.3\n// Workaround failure to string-cast null input\njQuery.parseJSON = function( data ) {\n\treturn JSON.parse( data + \"\" );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, tmp;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE9\n\ttry {\n\t\ttmp = new DOMParser();\n\t\txml = tmp.parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\t// Document location\n\tajaxLocParts,\n\tajaxLocation,\n\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat(\"*\");\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[0] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader(\"Content-Type\");\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[ \"throws\" ] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( (match = rheaders.exec( responseHeadersString )) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" )\n\t\t\t.replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) !==\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\tfireGlobals = s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger(\"ajaxStart\");\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout(function() {\n\t\t\t\t\tjqXHR.abort(\"timeout\");\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n});\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax({\n\t\turl: url,\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t});\n};\n\n\njQuery.fn.extend({\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[ 0 ] ) {\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t}\n});\n\n\njQuery.expr.filters.hidden = function( elem ) {\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0;\n};\njQuery.expr.filters.visible = function( elem ) {\n\treturn !jQuery.expr.filters.hidden( elem );\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function() {\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t})\n\t\t.map(function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new XMLHttpRequest();\n\t} catch( e ) {}\n};\n\nvar xhrId = 0,\n\txhrCallbacks = {},\n\txhrSuccessStatus = {\n\t\t// file protocol always yields status code 0, assume 200\n\t\t0: 200,\n\t\t// Support: IE9\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\n// Support: IE9\n// Open requests must be manually aborted on unload (#5280)\nif ( window.ActiveXObject ) {\n\tjQuery( window ).on( \"unload\", function() {\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]();\n\t\t}\n\t});\n}\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport(function( options ) {\n\tvar callback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr(),\n\t\t\t\t\tid = ++xhrId;\n\n\t\t\t\txhr.open( options.type, options.url, options.async, options.username, options.password );\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tdelete xhrCallbacks[ id ];\n\t\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\t// file: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\t\t\t\t\t\t\t\t\t// Support: IE9\n\t\t\t\t\t\t\t\t\t// Accessing binary-data responseText throws an exception\n\t\t\t\t\t\t\t\t\t// (#11426)\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText === \"string\" ? {\n\t\t\t\t\t\t\t\t\t\ttext: xhr.responseText\n\t\t\t\t\t\t\t\t\t} : undefined,\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\txhr.onerror = callback(\"error\");\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = xhrCallbacks[ id ] = callback(\"abort\");\n\n\t\t\t\t// Do send the request\n\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /(?:java|ecma)script/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery(\"<script>\").prop({\n\t\t\t\t\tasync: true,\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t}).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// data: string of html\n// context (optional): If specified, the fragment will be created in this context, defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\tcontext = context || document;\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[1] ) ];\n\t}\n\n\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = url.slice( off );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t}).length;\n};\n\n\n\n\nvar docElem = window.document.documentElement;\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf(\"auto\") > -1;\n\n\t\t// Need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend({\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each(function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t});\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\telem = this[ 0 ],\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\t// If we don't have gBCR, just use 0,0 rather than error\n\t\t// BlackBerry 5, iOS 3 (original iPhone)\n\t\tif ( typeof elem.getBoundingClientRect !== strundefined ) {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t}\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: box.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// We assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || docElem;\n\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\" ) === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || docElem;\n\t\t});\n\t}\n});\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : window.pageXOffset,\n\t\t\t\t\ttop ? val : window.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// getComputedStyle returns percent when specified for top/left/bottom/right\n// rather than make the css module depend on the offset module, we just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n});\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\treturn this.length;\n};\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t});\n}\n\n\n\n\nvar\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in\n// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === strundefined ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n\n}));\n"
  },
  {
    "path": "input-scripts/simple-scripts/function_function.js",
    "content": "var _createClass = function () {\n    function defineProperties(target, props) {\n        for (var i = 0; i < props.length; i++) {\n            var descriptor = props[i];\n            descriptor.enumerable = descriptor.enumerable || false;\n            descriptor.configurable = true;\n            if (\"value\" in descriptor)\n              descriptor.writable = true;\n              Object.defineProperty(target, descriptor.key, descriptor);\n          }\n      }\n      return function (Constructor, protoProps, staticProps) {\n        if (protoProps)\n         defineProperties(Constructor.prototype, protoProps);\n\n      if (staticProps)\n        defineProperties(Constructor, staticProps);\n\n      return Constructor;\n    }; \n}();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar Animal = function() {\n  function Animal(name, color) {\n    _classCallCheck(this, Animal);\n    this.name = name\n    this.color = color\n  }\n\n  _createClass(Animal, [{\n    key: 'fn',\n    get: function get() {\n      return function() {return this.color;};\n    }\n  }]);\n}();\n\nvar a = new Animal();\na.fn();\n"
  },
  {
    "path": "input-scripts/simple-scripts/functioncall-arithmetic.js",
    "content": "var x = 5;\n\nfunction f(a) {\n    return 2 * a;\n}\n\ny = f(x);\nf(2);\n\nfunction j(b) {\n  return f(b);\n}\n\nfunction g(h, y) {\n  j(4);\n  return h(y);\n}\n\ng(f, x + 8);\n"
  },
  {
    "path": "input-scripts/simple-scripts/jQuery.js",
    "content": "(function() {\n function jQuery(n) {\n  var res = Object.create(jQuery.fn);\n  var elts = document.getElementsByTagName(n);\n  for(var i=0;i<elts.length;++i)\n   res[i] = elts[i];\n  res.length = elts.length;\n  return res;\n }\n\n jQuery.fn = {\n  extend: function ext(obj) {\n   for(var p in obj)\n    jQuery.fn[p] = obj[p];\n  }\n };\n\n jQuery.fn.extend({\n  each: function(cb) {\n   for(var i=0;i<this.length;++i)\n    cb(this[i], i);\n  }\n });\n\n window.jQuery = jQuery;\n})();\n(function($) {\n  $.fn.highlightAlt = function(c) {\n    this.each(function(elt) {\n      for(var i=1;i<elt.children.length;i+=2)\n        elt.children[i].style.backgroundColor = c;\n    });\n  };\n\n  window.highlightAltRows = function() {\n    $('tbody').highlightAlt('#A9D0F5');\n  };\n})(jQuery);\n"
  },
  {
    "path": "input-scripts/simple-scripts/or_function.js",
    "content": "b = false\n\nb = b || function () {\n  return true;\n}();\n"
  },
  {
    "path": "input-scripts/simple-scripts/use_before_definition.js",
    "content": "Object.defineProperty(exports, \"__esModule\", {\n  value: true\n});\n\nexports.default = add;\nfunction add(x, y) {\n  return x + y;\n}\n"
  },
  {
    "path": "js-callgraph.js",
    "content": "#!/usr/bin/env node\n\n/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\nconst JCG = require(\"./src/runner\");\nconst ArgumentParser = require('argparse').ArgumentParser;\nconst fs = require('fs');\n\nlet argParser = new ArgumentParser({\n    addHelp: true,\n    description: 'Call graph generator'\n});\n\nargParser.addArgument(\n    ['--fg'],\n    {\n        nargs: 0,\n        help: 'print flow graph'\n    }\n);\n\nargParser.addArgument(\n    ['--cg'],\n    {\n        nargs: 0,\n        help: 'print call graph'\n    }\n);\n\nargParser.addArgument(\n    ['--time'],\n    {\n        nargs: 0,\n        help: 'print timings'\n    }\n);\n\nargParser.addArgument(\n    ['--strategy'],\n    {help: 'interprocedural propagation strategy; one of NONE, ONESHOT (default), DEMAND, and FULL (not yet implemented) '}\n);\n\nargParser.addArgument(\n    ['--countCB'],\n    {\n        nargs: 0,\n        help: 'Counts the number of callbacks.'\n    }\n);\n\nargParser.addArgument(\n    ['--reqJs'],\n    {\n        nargs: 0,\n        help: 'Make a RequireJS dependency graph.'\n    }\n);\n\nargParser.addArgument(\n    ['--output'],\n    {\n        nargs: 1,\n        help: 'The output file name, which contains the JSON of result. (extension: .json)'\n    }\n);\nargParser.addArgument(\n    ['--filter'],\n    {\n        nargs: 1,\n        help: 'The filters contains file. The syntax of filtering readable in README.md'\n    }\n);\n\nlet r = argParser.parseKnownArgs();\nconst args = r[0];\nconst inputList = r[1];\n\nJCG.setArgs(args);\nJCG.setFiles(inputList);\nif (args.filter !== null) {\n    let filter = [];\n    let filterFile = args.filter[0];\n    if (!fs.existsSync(filterFile)) {\n        console.warn('The path of filter file \"' + filterFile + '\" does not exists.');\n    } else {\n        let content = fs.readFileSync(filterFile, 'utf8').split(/\\r?\\n/);\n        let lineNumber = 0;\n        content.forEach(function (line) {\n            line = line.trim();\n            lineNumber++;\n\n            if (line.trim().length <= 1)\n                return;\n\n            if (!line.startsWith(\"#\")) {\n                if (line.startsWith(\"+\") || line.startsWith(\"-\")) {\n                    filter.push(line);\n                } else {\n                    console.warn(\"[\" + filterFile + \"] Line \" + lineNumber + \" contains a not valid filter: \" + line);\n                }\n            }\n        });\n        JCG.setFilter(filter);\n    }\n}\nJCG.setConsoleOutput(true);\n/*\n* The build return with a JSON of result.\n */\nJCG.build();\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@persper/js-callgraph\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Builds static call graph for Javascript with a field-based algorithm.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@babel/core\": \"^7.1.2\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.1.0\",\n    \"@babel/preset-flow\": \"^7.0.0\",\n    \"@babel/preset-typescript\": \"^7.1.0\",\n    \"JSONStream\": \"1.3.3\",\n    \"amdefine\": \"^1.0.1\",\n    \"argparse\": \"^1.0.10\",\n    \"babel-core\": \"^6.26.3\",\n    \"body-parser\": \"^1.18.2\",\n    \"esprima\": \"^4.0.0\",\n    \"express\": \"^4.16.3\",\n    \"npm\": \"^5.10.0\",\n    \"sloc\": \"^0.2.0\",\n    \"source-map\": \"^0.7.3\",\n    \"vue-parser\": \"^1.1.6\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.0.0\",\n    \"jest\": \"^23.1.0\"\n  },\n  \"scripts\": {\n    \"test\": \"jest && python3 ./tests/test.py\"\n  },\n  \"jest\": {\n    \"testRegex\": \"tests/jest/.*\\\\.(js|jsx)$\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Persper/js-callgraph.git\"\n  },\n  \"license\": \"EPL-2.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Persper/js-callgraph/issues\"\n  },\n  \"homepage\": \"https://github.com/Persper/js-callgraph#readme\",\n  \"keywords\": [\n    \"call graph\",\n    \"call\",\n    \"graph\",\n    \"ast\",\n    \"static analysis\"\n  ],\n  \"bin\": {\n    \"js-callgraph\": \"./js-callgraph.js\"\n  }\n}\n"
  },
  {
    "path": "saveSvgAsPng.js",
    "content": "(function() {\n  const out$ = typeof exports != 'undefined' && exports || typeof define != 'undefined' && {} || this || window;\n  if (typeof define !== 'undefined') define('save-svg-as-png', [], () => out$);\n  out$.default = out$;\n\n  const xmlNs = 'http://www.w3.org/2000/xmlns/';\n  const xhtmlNs = 'http://www.w3.org/1999/xhtml';\n  const svgNs = 'http://www.w3.org/2000/svg';\n  const doctype = '<?xml version=\"1.0\" standalone=\"no\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" [<!ENTITY nbsp \"&#160;\">]>';\n  const urlRegex = /url\\([\"']?(.+?)[\"']?\\)/;\n  const fontFormats = {\n    woff2: 'font/woff2',\n    woff: 'font/woff',\n    otf: 'application/x-font-opentype',\n    ttf: 'application/x-font-ttf',\n    eot: 'application/vnd.ms-fontobject',\n    sfnt: 'application/font-sfnt',\n    svg: 'image/svg+xml'\n  };\n\n  const isElement = obj => obj instanceof HTMLElement || obj instanceof SVGElement;\n  const requireDomNode = el => {\n    if (!isElement(el)) throw new Error(`an HTMLElement or SVGElement is required; got ${el}`);\n  };\n  const requireDomNodePromise = el =>\n    new Promise((resolve, reject) => {\n      if (isElement(el)) resolve(el)\n      else reject(new Error(`an HTMLElement or SVGElement is required; got ${el}`));\n    })\n  const isExternal = url => url && url.lastIndexOf('http',0) === 0 && url.lastIndexOf(window.location.host) === -1;\n\n  const getFontMimeTypeFromUrl = fontUrl => {\n    const formats = Object.keys(fontFormats)\n      .filter(extension => fontUrl.indexOf(`.${extension}`) > 0)\n      .map(extension => fontFormats[extension]);\n    if (formats) return formats[0];\n    console.error(`Unknown font format for ${fontUrl}. Fonts may not be working correctly.`);\n    return 'application/octet-stream';\n  };\n\n  const arrayBufferToBase64 = buffer => {\n    let binary = '';\n    const bytes = new Uint8Array(buffer);\n    for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);\n    return window.btoa(binary);\n  }\n\n  const getDimension = (el, clone, dim) => {\n    const v =\n      (el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal[dim]) ||\n      (clone.getAttribute(dim) !== null && !clone.getAttribute(dim).match(/%$/) && parseInt(clone.getAttribute(dim))) ||\n      el.getBoundingClientRect()[dim] ||\n      parseInt(clone.style[dim]) ||\n      parseInt(window.getComputedStyle(el).getPropertyValue(dim));\n    return typeof v === 'undefined' || v === null || isNaN(parseFloat(v)) ? 0 : v;\n  };\n\n  const getDimensions = (el, clone, width, height) => {\n    if (el.tagName === 'svg') return {\n      width: width || getDimension(el, clone, 'width'),\n      height: height || getDimension(el, clone, 'height')\n    };\n    else if (el.getBBox) {\n      const {x, y, width, height} = el.getBBox();\n      return {\n        width: x + width,\n        height: y + height\n      };\n    }\n  };\n\n  const reEncode = data =>\n    decodeURIComponent(\n      encodeURIComponent(data)\n        .replace(/%([0-9A-F]{2})/g, (match, p1) => {\n          const c = String.fromCharCode(`0x${p1}`);\n          return c === '%' ? '%25' : c;\n        })\n    );\n\n  const uriToBlob = uri => {\n    const byteString = window.atob(uri.split(',')[1]);\n    const mimeString = uri.split(',')[0].split(':')[1].split(';')[0]\n    const buffer = new ArrayBuffer(byteString.length);\n    const intArray = new Uint8Array(buffer);\n    for (let i = 0; i < byteString.length; i++) {\n      intArray[i] = byteString.charCodeAt(i);\n    }\n    return new Blob([buffer], {type: mimeString});\n  };\n\n  const query = (el, selector) => {\n    if (!selector) return;\n    try {\n      return el.querySelector(selector) || el.parentNode && el.parentNode.querySelector(selector);\n    } catch(err) {\n      console.warn(`Invalid CSS selector \"${selector}\"`, err);\n    }\n  };\n\n  const detectCssFont = (rule, href) => {\n    // Match CSS font-face rules to external links.\n    // @font-face {\n    //   src: local('Abel'), url(https://fonts.gstatic.com/s/abel/v6/UzN-iejR1VoXU2Oc-7LsbvesZW2xOQ-xsNqO47m55DA.woff2);\n    // }\n    const match = rule.cssText.match(urlRegex);\n    const url = (match && match[1]) || '';\n    if (!url || url.match(/^data:/) || url === 'about:blank') return;\n    const fullUrl =\n      url.startsWith('../') ? `${href}/../${url}`\n      : url.startsWith('./') ? `${href}/.${url}`\n      : url;\n    return {\n      text: rule.cssText,\n      format: getFontMimeTypeFromUrl(fullUrl),\n      url: fullUrl\n    };\n  };\n\n  const inlineImages = el => Promise.all(\n    Array.from(el.querySelectorAll('image')).map(image => {\n      let href = image.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || image.getAttribute('href');\n      if (!href) return Promise.resolve(null);\n      if (isExternal(href)) {\n        href += (href.indexOf('?') === -1 ? '?' : '&') + 't=' + new Date().valueOf();\n      }\n      return new Promise((resolve, reject) => {\n        const canvas = document.createElement('canvas');\n        const img = new Image();\n        img.crossOrigin = 'anonymous';\n        img.src = href;\n        img.onerror = () => reject(new Error(`Could not load ${href}`));\n        img.onload = () => {\n          canvas.width = img.width;\n          canvas.height = img.height;\n          canvas.getContext('2d').drawImage(img, 0, 0);\n          image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', canvas.toDataURL('image/png'));\n          resolve(true);\n        };\n      });\n    })\n  );\n\n  const cachedFonts = {};\n  const inlineFonts = fonts => Promise.all(\n    fonts.map(font =>\n      new Promise((resolve, reject) => {\n        if (cachedFonts[font.url]) return resolve(cachedFonts[font.url]);\n\n        const req = new XMLHttpRequest();\n        req.addEventListener('load', () => {\n          // TODO: it may also be worth it to wait until fonts are fully loaded before\n          // attempting to rasterize them. (e.g. use https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet)\n          const fontInBase64 = arrayBufferToBase64(req.response);\n          const fontUri = font.text.replace(urlRegex, `url(\"data:${font.format};base64,${fontInBase64}\")`)+'\\n';\n          cachedFonts[font.url] = fontUri;\n          resolve(fontUri);\n        });\n        req.addEventListener('error', e => {\n          console.warn(`Failed to load font from: ${font.url}`, e);\n          cachedFonts[font.url] = null;\n          resolve(null);\n        });\n        req.addEventListener('abort', e => {\n          console.warn(`Aborted loading font from: ${font.url}`, e);\n          resolve(null);\n        });\n        req.open('GET', font.url);\n        req.responseType = 'arraybuffer';\n        req.send();\n      })\n    )\n  ).then(fontCss => fontCss.filter(x => x).join(''));\n\n  let cachedRules = null;\n  const styleSheetRules = () => {\n    if (cachedRules) return cachedRules;\n    return cachedRules = Array.from(document.styleSheets).map(sheet => {\n      try {\n        return {rules: sheet.cssRules, href: sheet.href};\n      } catch (e) {\n        console.warn(`Stylesheet could not be loaded: ${sheet.href}`, e);\n        return {};\n      }\n    });\n  };\n\n  const inlineCss = (el, options) => {\n    const {\n      selectorRemap,\n      modifyStyle,\n      modifyCss,\n      fonts\n    } = options || {};\n    const generateCss = modifyCss || ((selector, properties) => {\n      const sel = selectorRemap ? selectorRemap(selector) : selector;\n      const props = modifyStyle ? modifyStyle(properties) : properties;\n      return `${sel}{${props}}\\n`;\n    });\n    const css = [];\n    const detectFonts = typeof fonts === 'undefined';\n    const fontList = fonts || [];\n    styleSheetRules().forEach(({rules, href}) => {\n      if (!rules) return;\n      Array.from(rules).forEach(rule => {\n        if (typeof rule.style != 'undefined') {\n          if (query(el, rule.selectorText)) css.push(generateCss(rule.selectorText, rule.style.cssText));\n          else if (detectFonts && rule.cssText.match(/^@font-face/)) {\n            const font = detectCssFont(rule, href);\n            if (font) fontList.push(font);\n          } else css.push(rule.cssText);\n        }\n      });\n    });\n\n    return inlineFonts(fontList).then(fontCss => css.join('\\n') + fontCss);\n  };\n\n  const downloadOptions = () => {\n    if (!navigator.msSaveOrOpenBlob && !('download' in document.createElement('a'))) {\n      return {popup: window.open()};\n    }\n  };\n\n  out$.prepareSvg = (el, options, done) => {\n    requireDomNode(el);\n    const {\n      left = 0,\n      top = 0,\n      width: w,\n      height: h,\n      scale = 1,\n      responsive = false,\n    } = options || {};\n\n    return inlineImages(el).then(() => {\n      let clone = el.cloneNode(true);\n      clone.style.backgroundColor = (options || {}).backgroundColor || el.style.backgroundColor;\n      const {width, height} = getDimensions(el, clone, w, h);\n\n      if (el.tagName !== 'svg') {\n        if (el.getBBox) {\n          if (clone.getAttribute('transform') != null) {\n            clone.setAttribute('transform', clone.getAttribute('transform').replace(/translate\\(.*?\\)/, ''));\n          }\n          const svg = document.createElementNS('http://www.w3.org/2000/svg','svg');\n          svg.appendChild(clone);\n          clone = svg;\n        } else {\n          console.error('Attempted to render non-SVG element', el);\n          return;\n        }\n      }\n\n      clone.setAttribute('version', '1.1');\n      clone.setAttribute('viewBox', [left, top, width, height].join(' '));\n      if (!clone.getAttribute('xmlns')) clone.setAttributeNS(xmlNs, 'xmlns', svgNs);\n      if (!clone.getAttribute('xmlns:xlink')) clone.setAttributeNS(xmlNs, 'xmlns:xlink', 'http://www.w3.org/1999/xlink');\n\n      if (responsive) {\n        clone.removeAttribute('width');\n        clone.removeAttribute('height');\n        clone.setAttribute('preserveAspectRatio', 'xMinYMin meet');\n      } else {\n        clone.setAttribute('width', width * scale);\n        clone.setAttribute('height', height * scale);\n      }\n\n      Array.from(clone.querySelectorAll('foreignObject > *')).forEach(foreignObject => {\n        foreignObject.setAttributeNS(xmlNs, 'xmlns', foreignObject.tagName === 'svg' ? svgNs : xhtmlNs);\n      });\n\n      return inlineCss(el, options).then(css => {\n        const style = document.createElement('style');\n        style.setAttribute('type', 'text/css');\n        style.innerHTML = `<![CDATA[\\n${css}\\n]]>`;\n\n        const defs = document.createElement('defs');\n        defs.appendChild(style);\n        clone.insertBefore(defs, clone.firstChild);\n\n        const outer = document.createElement('div');\n        outer.appendChild(clone);\n        const src = outer.innerHTML.replace(/NS\\d+:href/gi, 'xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href');\n\n        if (typeof done === 'function') done(src, width, height);\n        else return {src, width, height};\n      });\n    });\n  };\n\n  out$.svgAsDataUri = (el, options, done) => {\n    requireDomNode(el);\n    return out$.prepareSvg(el, options)\n      .then(({src, width, height}) => {\n          const svgXml = `data:image/svg+xml;base64,${window.btoa(reEncode(doctype+src))}`;\n          if (typeof done === 'function') {\n              done(svgXml, width, height);\n          }\n          return svgXml;\n      });\n  };\n\n  out$.svgAsPngUri = (el, options, done) => {\n    requireDomNode(el);\n    const {\n      encoderType = 'image/png',\n      encoderOptions = 0.8,\n      canvg\n    } = options || {};\n\n    const convertToPng = ({src, width, height}) => {\n      const canvas = document.createElement('canvas');\n      const context = canvas.getContext('2d');\n      const pixelRatio = window.devicePixelRatio || 1;\n\n      canvas.width = width * pixelRatio;\n      canvas.height = height * pixelRatio;\n      canvas.style.width = `${canvas.width}px`;\n      canvas.style.height = `${canvas.height}px`;\n      context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);\n\n      if (canvg) canvg(canvas, src);\n      else context.drawImage(src, 0, 0);\n\n      let png;\n      try {\n        png = canvas.toDataURL(encoderType, encoderOptions);\n      } catch (e) {\n        if ((typeof SecurityError !== 'undefined' && e instanceof SecurityError) || e.name === 'SecurityError') {\n          console.error('Rendered SVG images cannot be downloaded in this browser.');\n          return;\n        } else throw e;\n      }\n      if (typeof done === 'function') done(png, canvas.width, canvas.height);\n      return Promise.resolve(png);\n    }\n\n    if (canvg) return out$.prepareSvg(el, options).then(convertToPng);\n    else return out$.svgAsDataUri(el, options).then(uri => {\n      return new Promise((resolve, reject) => {\n        const image = new Image();\n        image.onload = () => resolve(convertToPng({\n          src: image,\n          width: image.width,\n          height: image.height\n        }));\n        image.onerror = () => {\n          reject(`There was an error loading the data URI as an image on the following SVG\\n${window.atob(uri.slice(26))}Open the following link to see browser's diagnosis\\n${uri}`);\n        }\n        image.src = uri;\n      })\n    });\n  };\n\n  out$.download = (name, uri, options) => {\n    if (navigator.msSaveOrOpenBlob) navigator.msSaveOrOpenBlob(uriToBlob(uri), name);\n    else {\n      const saveLink = document.createElement('a');\n      if ('download' in saveLink) {\n        saveLink.download = name;\n        saveLink.style.display = 'none';\n        document.body.appendChild(saveLink);\n        try {\n          const blob = uriToBlob(uri);\n          const url = URL.createObjectURL(blob);\n          saveLink.href = url;\n          saveLink.onclick = () => requestAnimationFrame(() => URL.revokeObjectURL(url));\n        } catch (e) {\n          console.error(e);\n          console.warn('Error while getting object URL. Falling back to string URL.');\n          saveLink.href = uri;\n        }\n        saveLink.click();\n        document.body.removeChild(saveLink);\n      } else if (options && options.popup) {\n        options.popup.document.title = name;\n        options.popup.location.replace(uri);\n      }\n    }\n  };\n\n  out$.saveSvg = (el, name, options) => {\n    const downloadOpts = downloadOptions(); // don't inline, can't be async\n    return requireDomNodePromise(el)\n      .then(el => out$.svgAsDataUri(el, options || {}))\n      .then(uri => out$.download(name, uri, downloadOpts));\n  };\n\n  out$.saveSvgAsPng = (el, name, options) => {\n    const downloadOpts = downloadOptions(); // don't inline, can't be async\n    return requireDomNodePromise(el)\n      .then(el => out$.svgAsPngUri(el, options || {}))\n      .then(uri => out$.download(name, uri, downloadOpts));\n  };\n})();\n"
  },
  {
    "path": "scripts/install-hooks",
    "content": "#!/usr/bin/env bash\n\nGIT_DIR=$(git rev-parse --git-dir)\n\necho \"Installing hooks...\"\n# this command creates symlink to our pre-commit script\nln -s ../../scripts/pre-commit $GIT_DIR/hooks/pre-commit\necho \"Done!\"\n"
  },
  {
    "path": "scripts/pre-commit",
    "content": "#!/usr/bin/env bash\n\nREPO_DIR=$(git rev-parse --show-toplevel)\n\necho \"Running pre-commit hook\"\n\nnpm test\n\n# $? stores exit value of the last command\nif [ $? -ne 0 ]; then\n echo \"Tests must pass before commit!\"\n exit 1\nfi\n"
  },
  {
    "path": "src/astutil.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\nconst esprima = require('esprima');\nconst fs = require('fs');\nconst vueParser = require('vue-parser');\nconst prep = require('./srcPreprocessor');\n\n/* AST visitor */\nfunction visit(root, visitor) {\n    function doVisit(nd, parent, childProp) {\n        if (!nd || typeof nd !== 'object')\n            return;\n\n        if (nd.type) {\n            var res = visitor(nd, doVisit, parent, childProp);\n            if (res === false)\n                return;\n        }\n\n        for (var p in nd) {\n            // skip over magic properties\n            if (!nd.hasOwnProperty(p) || p.match(/^(range|loc|attr|comments|raw)$/))\n                continue;\n            doVisit(nd[p], nd, p);\n        }\n    }\n\n    doVisit(root);\n}\n\n/* AST visitor with state */\nfunction visitWithState(root, visitor) {\n    const state = {\n        'withinDeclarator': false,\n        'withinParams': false\n    };\n\n    function doVisit(nd, parent, childProp) {\n        if (!nd || typeof nd !== 'object')\n            return;\n\n        if (nd.type) {\n            var res = visitor(nd, doVisit, state, parent, childProp);\n            if (res === false)\n                return;\n        }\n\n        for (var p in nd) {\n            // skip over magic properties\n            if (!nd.hasOwnProperty(p) || p.match(/^(range|loc|attr|comments|raw)$/))\n                continue;\n            doVisit(nd[p], nd, p);\n        }\n    }\n\n    doVisit(root);\n}\n\n/* Set up `attr` field that can be used to attach attributes to\n * nodes, and fill in `enclosingFunction` and `enclosingFile`\n * attributes. */\nfunction init(root) {\n    var enclosingFunction = null, enclosingFile = null;\n    // global collections containing all functions and all call sites\n    root.attr.functions = [];\n    root.attr.calls = [];\n    visit(root, function (nd, doVisit, parent, childProp) {\n        if (nd.type && !nd.attr)\n            nd.attr = {};\n\n        if (enclosingFunction)\n            nd.attr.enclosingFunction = enclosingFunction;\n        if (enclosingFile)\n            nd.attr.enclosingFile = enclosingFile;\n\n        if (nd.type === 'Program') {\n            enclosingFile = nd.attr.filename;\n        }\n\n        /* Method Definition (Case 1)\n\n        This case is covered by test case: tests/basics/method-def.truth\n\n        Example:\n\n            var obj = {\n                methodName: function () {\n                    return 42;\n                }\n            }\n\n        Esprima AST:\n\n            interface Property {\n                type: 'Property';\n                key: Expression;\n                computed: boolean;\n                value: Expression | null;\n                kind: 'get' | 'set' | 'init';\n                method: false;\n                shorthand: boolean;\n            }\n        */\n        if (nd.type === 'FunctionExpression' && parent.type === 'Property') {\n            if (!parent.computed) {\n                if (parent.key.type === 'Identifier'){\n                    nd.id = parent.key;\n                }\n                else if (parent.key.type === 'Literal') {\n                    // create a new `Identifier` AST node and set it to `FunctionExpression`'s id\n                    nd.id = {\n                        type: 'Identifier',\n                        name: parent.key.value,\n                        range: parent.key.range,\n                        loc: parent.key.loc\n                    };\n                }\n                else {\n                    console.log(\"WARNING: unexpected key type of 'Property'.\");\n                }\n            }\n            else\n                console.log(\"WARNING: Computed property for method definition, not yet supported.\");\n        }\n\n        if (nd.type === 'FunctionDeclaration' ||\n            nd.type === 'FunctionExpression'  ||\n            nd.type === 'ArrowFunctionExpression') {\n\n            root.attr.functions.push(nd);\n            nd.attr.parent = parent;\n            nd.attr.childProp = childProp;\n            var old_enclosingFunction = enclosingFunction;\n            enclosingFunction = nd;\n            doVisit(nd.id);\n            doVisit(nd.params);\n            doVisit(nd.body);\n            enclosingFunction = old_enclosingFunction;\n            return false;\n        }\n\n        /* Method Definition (Case 2)\n        Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions\n\n        Example:\n\n            class Apple {\n                color () {\n                    return 'red';\n                }\n            }\n\n        Esprima AST:\n\n            interface MethodDefinition {\n                type: 'MethodDefinition';\n                key: Expression | null;\n                computed: boolean;\n                value: FunctionExpression | null;\n                kind: 'method' | 'constructor';\n                static: boolean;\n            }\n        */\n        if (nd.type === 'MethodDefinition')\n            if (!nd.computed) {\n                if (nd.key.type === 'Identifier') {\n                    nd.value.id = nd.key;\n                }\n                else if (nd.key.type === 'Literal') {\n                    // this case is covered by test case: tests/unexpected/stringiterator.truth\n                    console.log(\"WARNING: invalid syntax, method name is of type Literal instead of Identifier.\");\n                }\n                else {\n                    console.log(\"WARNING: unexpected key type of 'MethodDefinition'.\");\n                }\n            }\n            else {\n                console.log(\"WARNING: Computed property for method definition, not yet supported.\");\n            }\n\n        if (nd.type === 'CallExpression' || nd.type === 'NewExpression')\n            root.attr.calls.push(nd);\n    });\n}\n\n/* Simple version of UNIX basename. */\nfunction basename(filename) {\n    if (!filename)\n        return \"<???>\";\n    var idx = filename.lastIndexOf('/');\n    if (idx === -1)\n        idx = filename.lastIndexOf('\\\\');\n    return filename.substring(idx + 1);\n}\n\nfunction isAnon(funcName) {\n    return funcName === \"anon\";\n}\n\n// func must be function node in ast\nfunction funcname(func) {\n    if (func === undefined)\n        console.log('WARNING: func undefined in astutil/funcname.');\n    else if (func.id === null)\n        return \"anon\";\n    else\n        return func.id.name;\n}\n\n// encFunc can be undefined\nfunction encFuncName(encFunc) {\n    if (encFunc === undefined) {\n        return \"global\";\n    } else if (encFunc.id === null)\n        return \"anon\";\n    else\n        return encFunc.id.name\n}\n\n/* Pretty-print position. */\nfunction ppPos(nd) {\n    return basename(nd.attr.enclosingFile) + \"@\" + nd.loc.start.line + \":\" + nd.range[0] + \"-\" + nd.range[1];\n}\n\n/* Build as AST from a collection of source files */\nfunction astFromFiles(files) {\n    const ast = {\n        type: 'ProgramCollection',\n        programs: [],\n        attr: {}\n    }\n\n    for (let file of files) {\n        let src = fs.readFileSync(file, 'utf-8');\n        ast.programs.push(buildProgram(file, src));\n    }\n    init(ast);\n    return ast;\n}\n\n/* Build an AST from file name and source code\nArgs:\n    fname - A string, the name of the source file\n      src - A string, the source code\n\nReturn:\n    If succeeded, return an ast node of type 'ProgramCollection'.\n    If failed, return null.\n*/\nfunction astFromSrc(fname, src) {\n    const prog = buildProgram(fname, src);\n    if (prog === null)\n        return null;\n    const ast = {\n        'type': 'ProgramCollection',\n        'programs': [prog],\n        'attr': {}\n    }\n    init(ast);\n    return ast;\n}\n\nfunction reportError(msg, err) {\n    console.log('-------------------------------------------');\n    console.log(msg);\n    console.log(err.stack);\n    console.log('-------------------------------------------');\n}\n\n/* Returns an ast node of type 'Program'\nTo avoid confusion caused by too many different parsing settings,\nplease call this function whenever possible instead of rewriting esprima.parseModule...\n*/\nfunction parse(src) {\n    return esprima.parseModule(src, {\n        loc: true,\n        range: true,\n        jsx: true\n    });\n}\n\n/* Parse a single source file and return its ast\nArgs:\n    fname - A string, the name of the source file\n      src - A string, the source code\n\nReturn:\n    If succeeded, return an ast node of type 'Program'.\n    If failed, return null.\n*/\nfunction buildProgram (fname, src) {\n    // trim hashbang\n    src = prep.trimHashbangPrep(src);\n    // extract script from .vue file\n    try {\n        if (fname.endsWith('.vue'))\n            src = vueParser.parse(src, 'script');\n    }\n    catch (err) {\n        reportError('WARNING: Extracting <script> from .vue failed.', err);\n        return null;\n    }\n\n    // transpile typescript\n    try {\n        if (fname.endsWith('.ts'))\n            src = prep.typescriptPrep(fname, src);\n    }\n    catch (err) {\n        reportError('WARNING: Transpiling typescript failed.', err);\n        return null;\n    }\n\n    // parse javascript\n    let prog;\n    try {\n        prog = parse(src);\n    }\n    catch(err) {\n        reportError('Warning: Esprima failed to parse ' + fname, err);\n        return null;\n    }\n    prog.attr = {filename: fname};\n    return prog;\n}\n\n// cf is used by getFunctions\nconst cf = funcObj => {\n    return funcObj.file + ':' +\n           funcObj.name + ':' +\n           funcObj.range[0] + ':' +\n           funcObj.range[1] + ':' +\n           (funcObj.charRange[1] - funcObj.charRange[0]);\n};\n\n/* Return a list of objects storing function info in root\n\nArgs:\n    root - An ast node of type 'ProgramCollection',\n         - the output of astFromSrc function,\n         - thus, root.programs.length is equal to 1\n    src  - A string, the corresponding source code of `root`\n\nReturns:\n    A list of objects, each with the following properties\n    {\n        'name': a valid function name | 'anon' | 'global',\n        'file': a valid file name,\n        'range': a list of two integers,\n        'code': code of the function | null (for global context),\n        'encFuncName': a valid function name | 'anon' | 'global' | null (for global context),\n        'cf': a string representing the colon format id\n    }\n*/\nfunction getFunctions(root, src) {\n    const funcs = [];\n    const funcNodes = root.attr.functions;\n\n    for (let i = 0; i < funcNodes.length; ++i) {\n        const fn = funcNodes[i];\n\n        // funcName\n        let funcName = funcname(fn);\n\n        // startLine && endLine\n        let startLine = fn.loc.start['line'];\n        let endLine = fn.loc.end['line'];\n\n        // name, file and range are for colon format id\n        // code and encFuncName are added for trackFunctions\n        funcs.push({\n            'name': funcName,\n            'file': fn.attr.enclosingFile,\n            'range': [startLine, endLine],\n            'charRange': fn.range,\n            'code': src.substring(fn.range[0], fn.range[1]),\n            'encFuncName': encFuncName(fn.attr.enclosingFunction)\n        });\n    }\n\n    // Add 'cf' property\n    funcs.forEach(funcObj => {\n        funcObj['cf'] = cf(funcObj);\n    });\n\n    // Create a fake function object for global context\n    console.assert(root.programs.length === 1);\n    let prog = root.programs[0];\n    funcs.push({\n        'name': 'global',\n        'file': prog.attr.filename,\n        'range': [prog.loc.start['line'], prog.loc.end['line']],\n        'charRange': null,\n        'code': null,\n        'encFuncName': null,\n        'cf': prog.attr.filename + ':global'\n    });\n\n    return funcs;\n}\n\n/* Check if nd is an assignment to module.exports\n\nArgs:\n    nd - an ast node\n\nReturns:\n    true if nd represents an assignment to module.exports, false otherwise\n\nRelevant docs:\n\n    interface MemberExpression {\n        type: 'MemberExpression';\n        computed: boolean;\n        object: Expression;\n        property: Expression;\n    }\n*/\nfunction isModuleExports(nd) {\n    if (nd.type !== 'AssignmentExpression')\n        return false;\n\n    let left = nd.left;\n\n    if (left.type !== 'MemberExpression')\n        return  false;\n\n    let object = left.object;\n    let property = left.property;\n\n    if (object.type !== 'Identifier' || property.type !== 'Identifier')\n        return false;\n\n    return object.name === 'module' && property.name === 'exports';\n}\n\n/*\nArgs:\n       nd - an ast node\n  fn_name - a function name to compare to\n\nReturns: true if nd represents a call to fn_name, false otherwise\n\nRelevant docs:\n\n    interface CallExpression {\n        type: 'CallExpression';\n        callee: Expression;\n        arguments: ArgumentListElement[];\n    }\n*/\nfunction isCallTo(nd, fn_name) {\n    if (nd.type !== 'CallExpression')\n        return false;\n\n    let callee = nd.callee;\n\n    if (callee.type !== 'Identifier')\n        return false;\n\n    return callee.name === fn_name\n}\n\n/*\nArgs:\n       fn - an ast node representing a FunctionDeclaration\n\nReturns:\n    A list containing all of the ReturnStatement nodes' values in fn's body\n\nRelevant docs:\n\n    interface FunctionDeclaration {\n        type: 'FunctionDeclaration';\n        id: Identifier | null;\n        params: FunctionParameter[];\n        body: BlockStatement;\n        generator: boolean;\n        async: boolean;\n        expression: false;\n    }\n\n    interface BlockStatement {\n        type: 'BlockStatement';\n        body: StatementListItem[];\n    }\n\n    interface ReturnStatement {\n        type: 'ReturnStatement';\n        argument: Expression | null;\n    }\n*/\nfunction getReturnValues(fn) {\n    let lst = [];\n    let fn_body = fn.body;\n    /* There're two cases here:\n    Case 1. fn_body is of type 'BlockStatement'\n        this is the most common case, for example\n        const f = () => {return 1;};\n    Case 2. fn_body is not of type 'BlockStatement'\n        this case is covered by test case:\n            tests/import-export/define/arrow-func-no-block-statement-require.truth\n        const f = () => 1;\n\n        Esprima output:\n        {\n            \"type\": \"Program\",\n            \"body\": [\n                {\n                    \"type\": \"VariableDeclaration\",\n                    \"declarations\": [\n                        {\n                            \"type\": \"VariableDeclarator\",\n                            \"id\": {\n                                \"type\": \"Identifier\",\n                                \"name\": \"f\"\n                            },\n                            \"init\": {\n                                \"type\": \"ArrowFunctionExpression\",\n                                \"id\": null,\n                                \"params\": [],\n                                \"body\": {\n                                    \"type\": \"Literal\",\n                                    \"value\": 1,\n                                    \"raw\": \"1\"\n                                },\n                                \"generator\": false,\n                                \"expression\": true,\n                                \"async\": false\n                            }\n                        }\n                    ],\n                    \"kind\": \"const\"\n                }\n            ],\n            \"sourceType\": \"script\"\n        }\n    */\n    if (fn_body.type === 'BlockStatement') {\n        let block = fn_body.body;\n        for (var i = 0; i < block.length; i++)\n                if (block[i].type === 'ReturnStatement')\n                    lst.push(block[i].argument);\n    }\n    else {\n        lst.push(fn_body);\n    }\n    return lst;\n}\n\n/*\nArgs:\n    nd - An ast node\n\nReturns:\n    A boolean, true if nd is a function declaration\n    or function expression or arrow function expression,\n    false otherwise.\n*/\nfunction isFunction(nd) {\n   return nd.type === 'FunctionDeclaration' ||\n          nd.type === 'FunctionExpression' ||\n          nd.type === 'ArrowFunctionExpression'\n}\n\nmodule.exports.visit = visit;\nmodule.exports.visitWithState = visitWithState;\nmodule.exports.init = init;\nmodule.exports.ppPos = ppPos;\nmodule.exports.funcname = funcname;\nmodule.exports.encFuncName = encFuncName;\nmodule.exports.astFromFiles = astFromFiles;\nmodule.exports.astFromSrc = astFromSrc;\nmodule.exports.parse = parse;\nmodule.exports.getFunctions = getFunctions;\nmodule.exports.isAnon = isAnon;\nmodule.exports.isModuleExports = isModuleExports;\nmodule.exports.isCallTo = isCallTo;\nmodule.exports.getReturnValues = getReturnValues;\nmodule.exports.isFunction= isFunction;\nmodule.exports.cf= cf;\n"
  },
  {
    "path": "src/bindings.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Name bindings for lexical variables. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var astutil = require('./astutil'),\n        symtab = require('./symtab');\n\n    function addBindings(ast) {\n        var global_scope = new symtab.Symtab();\n        global_scope.global = true;\n        var scope = global_scope;\n        var decl_scope = scope;\n        astutil.visitWithState(ast,\n            function enter(nd, doVisit, state) {\n                switch (nd.type) {\n                    case 'FunctionDeclaration':\n                        /* This check is needed for:\n                                export function () { ... }\n                           as it will not have an id but will be\n                           a FunctionDeclaration in ES6 */\n                        if (nd.id) {\n                          decl_scope.set(nd.id.name, nd.id);\n                          doVisit(nd.id);\n                        }\n                    // FALL THROUGH\n                    case 'FunctionExpression':\n                    case 'ArrowFunctionExpression':\n                        var old_decl_scope = decl_scope;\n                        scope = decl_scope = new symtab.Symtab(scope);\n                        scope.global = false;\n\n                        nd.attr.scope = scope;\n                        if (( nd.type === 'FunctionExpression' ||\n                              nd.type === 'ArrowFunctionExpression' ) && nd.id) {\n                            decl_scope.set(nd.id.name, nd.id);\n                            doVisit(nd.id);\n                        }\n                        // Put params into symbol table\n                        decl_scope.set('this',\n                            {\n                                type: 'Identifier',\n                                name: 'this',\n                                loc: nd.loc,\n                                range: nd.range,\n                                attr: {\n                                    enclosingFile: nd.attr.enclosingFile,\n                                    scope: decl_scope\n                                }\n                            }\n                        );\n\n                        state['withinParams'] = true;\n                        for (var i = 0; i < nd.params.length; ++i) {\n                            // Handle identifer as before\n                            if (nd.params[i].type === 'Identifier')\n                                decl_scope.set(nd.params[i].name, nd.params[i]);\n\n                            // Always visit nd.params[i]\n                            // Case 1: If nd.params[i] is an Identifer, visit it to set its scope attribute\n                            // Case 2: If nd.params[i] is not an Identifer, visit it to set decl_scope\n                            doVisit(nd.params[i]);\n                        }\n                        state['withinParams'] = false;\n\n                        doVisit(nd.body);\n\n                        // restore previous scope\n                        if (!decl_scope.hasOwn('arguments'))\n                            decl_scope.set('arguments',\n                                {\n                                    type: 'Identifier',\n                                    name: 'arguments',\n                                    loc: nd.loc,\n                                    range: nd.range,\n                                    attr: {\n                                        enclosingFile: nd.attr.enclosingFile,\n                                        scope: decl_scope\n                                    }\n                                }\n                            );\n                        scope = scope.outer;\n                        decl_scope = old_decl_scope;\n\n                        return false;\n\n                    case 'CatchClause':\n                        scope = new symtab.Symtab(scope);\n                        scope.global = false;\n                        scope.set(nd.param.name, nd.param);\n\n                        doVisit(nd.param);\n                        doVisit(nd.body);\n\n                        scope = scope.outer;\n                        return false;\n\n                    case 'Identifier':\n                    case 'ThisExpression':\n                        nd.attr.scope = decl_scope;\n                        break;\n\n                    case 'MemberExpression':\n                        /*\n                        If computed === true,\n                        the node corresponds to a computed e1[e2] expression\n                        and property is an Expression.\n                        If computed === false,\n                        the node corresponds to a static e1.x expression\n                        and property is an Identifier.\n                        */\n                        doVisit(nd.object);\n                        if (nd.computed)\n                            doVisit(nd.property);\n                        return false;\n\n                    case 'VariableDeclarator':\n                        // If nd.id is an Identifer and its name hasn't been declared in the scope, set its name in the scope\n                        // Re-declaration of a variable in the same scope is ignored\n                        if (nd.id.type === 'Identifier' && !decl_scope.hasOwn(nd.id.name))\n                            decl_scope.set(nd.id.name, nd.id);\n\n                        // visit both nd.id and nd.init\n                        // nd.id\n                        //     Case 1: If nd.id is an Identifer, visit it and set its scope attribute\n                        //     Case 2: If nd.id is a BindingPattern, visit it to extract declarations\n                        // nd.init might contain function expression\n                        state['withinDeclarator'] = true;\n                        doVisit(nd.id)\n                        doVisit(nd.init)\n                        state['withinDeclarator'] = false;\n                        return false;\n\n                    case 'ObjectPattern':\n                        // ES6 Object Destructuring\n                        // { key: value }\n                        // The newly declared name is always in value\n                        // Haven't tested with rest and default params\n\n                        // Only visit this node if it's\n                        // within VariableDeclarator or\n                        // within params\n                        for (let prop of nd.properties) {\n                            if ((state['withinDeclarator'] || state['withinParams']) &&\n                                prop.value.type === 'Identifier' &&\n                                !decl_scope.hasOwn(prop.value.name))\n                                decl_scope.set(prop.value.name, prop.value);\n\n                            doVisit(prop.value);\n                        }\n                        return false;\n\n                    case 'ArrayPattern':\n                        // ES6 Array Destructuring\n                        // Haven't tested with rest and default params\n\n                        // Only visit this node if it's\n                        // within VariableDeclarator or\n                        // within params\n                        for (let elm of nd.elements) {\n                            // Array destructuring can ignore some values, so check null first\n                            if (elm) {\n                                if ((state['withinDeclarator'] || state['withinParams']) &&\n                                    elm.type === 'Identifier' &&\n                                    !decl_scope.hasOwn(elm.name))\n                                    decl_scope.set(elm.name, elm);\n\n                                doVisit(elm);\n                            }\n                        }\n                        return false;\n\n                    case 'Property':\n                        // Temporary fix for computed property names\n                        // visit nd.key to avoid scope of identifer in computed property names being undefined\n                        doVisit(nd.key);\n                        doVisit(nd.value);\n                        return false;\n                }\n            });\n    }\n\n    exports.addBindings = addBindings;\n    return exports;\n});\n"
  },
  {
    "path": "src/bitset.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/**\n * Implementation of sets of non-negative integers as bitsets.\n */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    // Wegner's algorithm\n    function countBitsInWord(w) {\n        var cnt = 0;\n        while (w) {\n            ++cnt;\n            w &= w - 1;\n        }\n        return cnt;\n    }\n\n    function countBits(a) {\n        var cnt = 0;\n        a.forEach(function (w) {\n            cnt += countBitsInWord(w);\n        });\n        return cnt;\n    }\n\n    function size(a) {\n        if (typeof a === 'undefined')\n            return 0;\n\n        if (typeof a === 'number')\n            return 1;\n\n        return countBits(a);\n    }\n\n    /**\n     * Check whether set a contains number x.\n     */\n    function contains(a, x) {\n        if (typeof a === 'undefined')\n            return false;\n\n        if (typeof a === 'number')\n            return a === x;\n\n        var word_off = x >> 5,\n            word_idx = x % 32;\n\n        if (word_off >= a.length)\n            return false;\n\n        return !!(a[word_off] & (1 << word_idx));\n    }\n\n    function createSingletonBitset(x) {\n        var word_off = x >> 5,\n            word_idx = x % 32;\n        var a = new Array(word_off + 1);\n        a[word_off] = (1 << word_idx);\n        return a;\n    }\n\n    /**\n     * Add number x to set a, and return the possibly modified a.\n     */\n    function add(a, x) {\n        if (typeof a === 'undefined')\n            return x;\n\n        if (typeof a === 'number')\n            a = createSingletonBitset(a);\n\n        var word_off = x >> 5,\n            word_idx = x % 32;\n        a[word_off] = (a[word_off] || 0) | (1 << word_idx);\n        return a;\n    }\n\n    /**\n     * Add all elements in set b to set a, returning the resulting set.\n     * While set a may be modified, set b never is.\n     */\n    function addAll(a, b) {\n        if (typeof a === 'undefined')\n            return copy(b);\n\n        if (typeof b === 'undefined')\n            return a;\n\n        if (typeof b === 'number')\n            return add(a, b);\n\n        if (typeof a === 'number')\n            return add(copy(b), a);\n\n        // both a and b must be bitsets\n        for (var i = 0; i < b.length; ++i)\n            if (b[i])\n                a[i] = (a[i] || 0) | b[i];\n        return a;\n    }\n\n    function remove(a, x) {\n        if (typeof a === 'undefined')\n            return a;\n\n        if (typeof a === 'number')\n            return a === x ? void(0) : a;\n\n        var word_off = x >> 5,\n            word_idx = x % 32;\n        a[word_off] = (a[word_off] || 0) & ~(1 << word_idx);\n        return a;\n    }\n\n    function removeAll(a, b) {\n        if (typeof a === 'undefined' || typeof b === 'undefined')\n            return a;\n\n        if (typeof a === 'number')\n            return contains(b, a) ? void(0) : a;\n\n        if (typeof b === 'number')\n            return remove(a, b);\n\n        a.forEach(function (w, i) {\n            if (b[i])\n                a[i] = a[i] & ~b[i];\n        });\n        return a;\n    }\n\n    function copy(a) {\n        if (typeof a === 'undefined' || typeof a === 'number')\n            return a;\n\n        return a.slice(0);\n    }\n\n    function iter(a, cb) {\n        if (a) {\n            if (typeof a === 'number')\n                cb(a);\n            else\n                a.forEach(function (w, i) {\n                    for (var j = 0; j < 32; ++j)\n                        if (w & (1 << j))\n                            cb(32 * i + j);\n                });\n        }\n    }\n\n    function map(a, f) {\n        if (a) {\n            if (typeof a === 'number')\n                return [f(a)];\n            else {\n                var res = [];\n                iter(a, function (x) {\n                    res[res.length] = f(x);\n                })\n                return res;\n            }\n        } else {\n            return [];\n        }\n    }\n\n    function some(a, f) {\n        if (a) {\n            if (typeof a === 'number')\n                return f(a);\n            else\n                for (var i = 0; i < a.length; ++i)\n                    if (a[i])\n                        for (var j = 0; j < 32; ++j)\n                            if (a[i] & (1 << j))\n                                if (f(32 * i + j))\n                                    return true;\n        }\n        return false;\n    }\n\n    function all(a, f) {\n        if (a) {\n            if (typeof a === 'number')\n                return f(a);\n            else\n                for (var i = 0; i < a.length; ++i)\n                    if (a[i])\n                        for (var j = 0; j < 32; ++j)\n                            if (a[i] & (1 << j))\n                                if (!f(32 * i + j))\n                                    return false;\n        }\n        return true;\n    }\n\n    function fromArray(ary) {\n        var a;\n        ary.forEach(function (x) {\n            a = add(a, x);\n        });\n        return a;\n    }\n\n    function toArray(a) {\n        return map(a, function f(x) {\n            return x;\n        });\n    }\n\n    exports.copy = copy;\n    exports.size = size;\n    exports.contains = contains;\n    exports.add = add;\n    exports.addAll = addAll;\n    exports.remove = remove;\n    exports.removeAll = removeAll;\n    exports.iter = iter;\n    exports.map = map;\n    exports.some = some;\n    exports.all = all;\n    exports.fromArray = fromArray;\n    exports.toArray = toArray;\n    return exports;\n});\n"
  },
  {
    "path": "src/callbackCounter.js",
    "content": "if (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function(require, exports) {\n    var astutil = require('./astutil'),\n        graph = require('./graph');\n\n    exports.countCallbacks = function(ast) {\n        var callbacks = [], callbackUses = 0;\n        var enclosingFunctionParameters = [];\n        var functionDeclarationParameter = 0, functionExpressionParameter = 0;\n        astutil.visit(ast, function(node) {\n            switch (node.type) {\n                case 'CallExpression' :\n                    //FIND ARGUMENT AS PARAMETER IN ENCLOSING FUNCTION.\n                    var callee = node.callee, functionName = callee.name;\n                    var enclosingFunctionParameter = findEnclosingFunctionParameter(callee, functionName);\n                    if (enclosingFunctionParameter !== null) {\n                        callbackUses++;\n                        if (enclosingFunctionParameters.indexOf(enclosingFunctionParameter) === -1) {\n                            callbacks.push(node);\n                            enclosingFunctionParameters.push(enclosingFunctionParameter);\n                        }\n                    }\n                break;\n\n                case 'FunctionDeclaration' :\n                    functionDeclarationParameter += node.params.length;\n                break;\n\n                case 'FunctionExpression' :\n                    functionExpressionParameter += node.params.length;\n                break;\n            }\n        });\n        var totalParameters = functionDeclarationParameter + functionExpressionParameter;\n        var callbackPercentage = callbacks.length / totalParameters * 100;\n        console.log(\"I found \" + callbacks.length + \" callbacks and \" + callbackUses + \" call back uses. In total we have \" + functionDeclarationParameter + \" function declaration parameters and \" + functionExpressionParameter + \" function expression parameters.\");\n        console.log(\"This makes a total of \" + totalParameters + \" parameters. Which means that (counting each function once as a callback) \" + callbackPercentage + \" percent of parameters are callbacks.\");\n    };\n\n    function findEnclosingFunctionParameter(node, functionName) {\n        var enclosingFunction = node.attr.enclosingFunction;\n        if (!enclosingFunction) {\n            return null;\n        }\n\n        var matchingParameter = findFirst(enclosingFunction.params, isParameterWithName(functionName));\n        if (matchingParameter !== null) {\n            return matchingParameter;\n        }\n\n        return findEnclosingFunctionParameter(enclosingFunction, functionName);\n    }\n\n    function findFirst(array, predicate) {\n        var soughtElement = null;\n        array.forEach(function(element) {\n            if (predicate(element) === true) {\n                soughtElement = element;\n                return false;\n            }\n        });\n        return soughtElement;\n    }\n\n    function isParameterWithName(functionName) {\n        return function(parameter) {\n            return parameter.name === functionName;\n        };\n    }\n\n    return exports;\n});"
  },
  {
    "path": "src/callgraph.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Module for extracting a call graph from a flow graph. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var graph = require('./graph'),\n        dftc = require('./dftc.js'),\n        flowgraph = require('./flowgraph');\n\n    // extract a call graph from a flow graph by collecting all function vertices that are inversely reachable from a callee vertex\n    function extractCG(ast, flow_graph) {\n        var edges = new graph.Graph(),\n            escaping = [], unknown = [];\n\n        var reach = dftc.reachability(flow_graph, function (nd) {\n            return nd.type !== 'UnknownVertex';\n        });\n\n        /* fn is a flow graph node of type 'FuncVertex' */\n        function processFuncVertex(fn) {\n            var r = reach.getReachable(fn);\n            r.forEach(function (nd) {\n                if (nd.type === 'UnknownVertex')\n                    escaping[escaping.length] = fn;\n                else if (nd.type === 'CalleeVertex')\n                    edges.addEdge(nd, fn);\n            });\n        }\n\n        /*\n        ast.attr.functions.forEach(function (fn) {\n            processFuncVertex(flowgraph.funcVertex(fn));\n        });\n        */\n\n        flow_graph.iterNodes(function (nd) {\n            if (nd.type === 'FuncVertex'){\n                processFuncVertex(nd);\n            }\n        });\n\n        flowgraph.getNativeVertices().forEach(processFuncVertex);\n\n        var unknown_r = reach.getReachable(flowgraph.unknownVertex());\n        unknown_r.forEach(function (nd) {\n            if (nd.type === 'CalleeVertex')\n                unknown[unknown.length] = nd;\n        });\n\n        return {\n            edges: edges,\n            escaping: escaping,\n            unknown: unknown,\n            fg: flow_graph\n        };\n    }\n\n    exports.extractCG = extractCG;\n    return exports;\n});\n"
  },
  {
    "path": "src/dftc.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/**\n * This module implements the depth-first transitive closure algorithm of\n * Ioannidis and Ramakrishnan (\"Efficient Transitive Closure Algorithms\", VLDB '88).\n */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n  const { nd2str } = require('./graph');\n\n    exports.reachability = function (graph, nodePred) {\n        let enum_nodes = new Array();\n\n        let nodes = graph.getNodes();\n\n        let n = nodes.length;\n\n        const str2rid = {};\n\n        for (let i = 0; i < n; i++) {\n            enum_nodes[i] = nodes[i];\n            str2rid[nd2str(nodes[i])] = i;\n        }\n\n        let visited = new Array(n).fill(0),\n           visited2 = new Array(n).fill(0),\n             popped = new Array(n).fill(0),\n             globol = new Set(),\n                  m = [],\n                  t = [];\n\n        for (let i = 0; i < n; i++) {\n            m.push(new Set());\n            t.push(new Set());\n        }\n\n        function visit1(i) {\n            visited[i] = 1;\n\n            if (!nodePred || nodePred(enum_nodes[i])) {\n                let succ = graph.succ(enum_nodes[i])\n\n                for (let j= 0; j < succ.length; j++) {\n                  let index = str2rid[nd2str(succ[j])];\n                  if (nodePred && !nodePred(succ[j]))\n                    continue;\n                  if (m[i].has(index) || t[i].has(index))\n                    continue;\n\n                  if (visited[index] == 0)\n                    visit1(index);\n\n                  if (popped[index] == 1) {\n                    m[i] = new Set(m[i])\n                    for (let elem of m[index].values()) {\n                      m[i].add(elem);\n                    }\n                    m[i].add(index);\n                    t[i] = new Set(t[i])\n                    for (let elem of t[index].values())\n                      t[i].add(elem);\n                    for (let elem of m[i].values())\n                      t[i].delete(elem);\n                  } else {\n                    t[i] = new Set(t[i].add(index));\n                  }\n                }\n              }\n\n            if(t[i].has(i)) {\n              if (t[i].size === 1) {\n                m[i].add(i);\n                t[i] = new Set();\n                globol = new Set(m[i]);\n                visit2(i);\n              } else {\n                t[i].delete(i);\n                m[i].add(i);\n              }\n            }\n\n            popped[i] = 1;\n        }\n\n        function visit2(i) {\n            visited2[i] = 1;\n\n            if (!nodePred || nodePred(enum_nodes[i])) {\n              let succ = graph.succ(enum_nodes[i])\n\n              for (let j= 0; j < succ.length; j++) {\n                let index = str2rid[nd2str(succ[j])];\n                if (nodePred && !nodePred(succ[j]))\n                  return;\n                if (visited2[index] == 0 && t[index].size !== 0)\n                  visit2(index);\n              }\n            }\n\n            m[i] = new Set(globol);\n            t[i] = new Set();\n        }\n        return {\n            getReachable: function (src) {\n                const nodeStr = nd2str(src);\n                if (!(nodeStr in str2rid)) {\n                  enum_nodes.push(src);\n                  visited.push(0);\n                  visited2.push(0);\n                  popped.push(0);\n                  m.push(new Set());\n                  t.push(new Set());\n                  str2rid[nodeStr] = enum_nodes.length - 1;\n                }\n                const src_id = str2rid[nodeStr];\n\n                if (visited[src_id] == 0)\n                    visit1(src_id);\n\n                var tc = new Set(m[src_id]);\n                for (let elem of t[src_id].values())\n                  tc.add(elem);\n\n                let ret = new Array();\n                for (let elem of tc.values()) {\n                  ret.push(enum_nodes[elem]);\n                }\n\n                return ret;\n            },\n            iterReachable: function (src, cb) {\n              const nodeStr = nd2str(src);\n              if (!(nodeStr in str2rid)) {\n                enum_nodes.push(src);\n                visited.push(0);\n                visited2.push(0);\n                popped.push(0);\n                m.push(new Set());\n                t.push(new Set());\n                str2rid[nodeStr] = enum_nodes.length - 1;\n              }\n              const src_id = str2rid[nodeStr];\n\n              if (visited[src_id] == 0)\n                  visit1(src_id);\n\n              var tc = new Set(m[src_id]);\n              for (let elem of t[src_id].values())\n                tc.add(elem);\n\n              for (let elem of tc.values())\n                  cb(enum_nodes[elem]);\n            },\n            reaches: function (src, dest) {\n              const src_id = str2rid[nd2str(src)];\n              const dest_id = str2rid[nd2str(dest)];\n\n                if (visited[src_id] == 0)\n                    visit1(src_id);\n\n                var tc = new Set(m[src_id]);\n                for (let elem of t[src_id].values())\n                  tc.add(elem);\n\n                return tc.has(dest_id);\n            }\n        };\n    };\n    return exports;\n});\n"
  },
  {
    "path": "src/diagnostics.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Module for converting a graph into DOT format. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var graph = require('./graph'),\n        fs = require('fs');\n\n    graph.Graph.prototype.dotify = function () {\n        var res = \"\";\n        res += \"digraph FG {\\n\";\n        this.iter(function (from, to) {\n            res += '  \"' + from.attr.pp() + '\" -> \"' + to.attr.pp() + '\";\\n';\n        });\n        res += \"}\\n\";\n        return res;\n    };\n\n    graph.Graph.prototype.writeDOTFile = function (fn) {\n        fs.writeFileSync(fn, this.dotify());\n    };\n\n    return exports;\n});\n"
  },
  {
    "path": "src/flowgraph.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/**\n * This module defines the machinery for extracting a flow graph from an AST.\n */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var astutil = require('./astutil'),\n        graph = require('./graph'),\n        symtab = require('./symtab');\n\n    /* Set up intraprocedural flow */\n    function addIntraproceduralFlowGraphEdges(ast, flow_graph) {\n        flow_graph = flow_graph || new graph.FlowGraph();\n        astutil.visit(ast, function (nd) {\n            switch (nd.type) {\n                case 'ArrayExpression':\n                    for (var i = 0; i < nd.elements.length; ++i)\n                        if (nd.elements[i])\n                            flow_graph.addEdge(vertexFor(nd.elements[i]), propVertex({ type: 'Literal',\n                                value: i }));\n                    break;\n\n                // R1\n                case 'AssignmentExpression':\n                    if (nd.operator === '=')\n                        flow_graph.addEdges(vertexFor(nd.right), [vertexFor(nd.left), vertexFor(nd)]);\n                    break;\n\n                // R9\n                case 'CallExpression':\n                    if (nd.callee.type === 'MemberExpression')\n                        flow_graph.addEdge(vertexFor(nd.callee.object), argVertex(nd, 0));\n\n                // R8 FALL THROUGH\n                case 'NewExpression':\n                    flow_graph.addEdge(vertexFor(nd.callee), calleeVertex(nd));\n                    for (var i = 0; i < nd.arguments.length; ++i)\n                        flow_graph.addEdge(vertexFor(nd.arguments[i]), argVertex(nd, i + 1));\n                    flow_graph.addEdge(resVertex(nd), vertexFor(nd));\n                    break;\n\n                case 'CatchClause':\n                    flow_graph.addEdge(unknownVertex(), varVertex(nd.param));\n                    break;\n\n                // R3\n                case 'ConditionalExpression':\n                    flow_graph.addEdge(vertexFor(nd.consequent), vertexFor(nd));\n                    flow_graph.addEdge(vertexFor(nd.alternate), vertexFor(nd));\n                    break;\n\n                // R7\n                case 'ClassDeclaration':\n                case 'ClassExpression':\n                    var body = nd.body.body;\n                    if (nd.id)\n                        for (let i = 0; i < body.length; ++i)\n                            if (body[i].kind === 'constructor')\n                                flow_graph.addEdge(funcVertex(body[i].value), vertexFor(nd.id));\n                    break;\n\n                case 'FunctionDeclaration':\n                    /* This check is needed for:\n                            export function () { ... }\n                       as it will not have an id but will be\n                       a FunctionDeclaration in ES6 */\n                    if (nd.id)\n                      flow_graph.addEdge(funcVertex(nd), vertexFor(nd.id));\n                    break;\n\n                // R6\n                case 'FunctionExpression':\n                case 'ArrowFunctionExpression':\n                    flow_graph.addEdge(funcVertex(nd), exprVertex(nd));\n                    if (nd.id)\n                        flow_graph.addEdge(funcVertex(nd), varVertex(nd.id));\n                    break;\n\n                // R2, R4\n                case 'LogicalExpression':\n                    if (nd.operator === '||')\n                        flow_graph.addEdge(vertexFor(nd.left), vertexFor(nd));\n                    flow_graph.addEdge(vertexFor(nd.right), vertexFor(nd));\n                    break;\n\n                // R5\n                case 'ObjectExpression':\n                    nd.properties.forEach(function (prop) {\n                        if (prop.kind === 'init') {\n                            // Temporary fix for computed property names\n                            if (prop.key.type === 'Identifier' || prop.key.type == 'Literal')\n                                flow_graph.addEdge(vertexFor(prop.value), propVertex(prop.key));\n                        }\n                    });\n                    break;\n\n                // R10\n                case 'ReturnStatement':\n                    if (nd.argument)\n                        flow_graph.addEdge(vertexFor(nd.argument), retVertex(nd.attr.enclosingFunction));\n                    break;\n\n                case 'SequenceExpression':\n                    flow_graph.addEdge(vertexFor(nd.expressions[nd.expressions.length - 1]), vertexFor(nd));\n                    break;\n\n                case 'ThrowStatement':\n                    flow_graph.addEdge(vertexFor(nd.argument), unknownVertex());\n                    break;\n\n                case 'VariableDeclarator':\n                    // Only handle the case that nd.id is an Identifer\n                    // ObjectPattern and ArrayPattern are handled separately\n                    if (nd.id.type === 'Identifier' && nd.init)\n                        flow_graph.addEdge(vertexFor(nd.init), vertexFor(nd.id));\n                    break;\n\n                // ES6 rule, similar to object expression\n                // Currently don't support rest and default params\n                case 'ObjectPattern':\n                    for (let prop of nd.properties)\n                        // Assuming prop.key and prop.value are Identifers\n                        flow_graph.addEdge(propVertex(prop.key), vertexFor(prop.value));\n                    break;\n\n                // ES6 rule, similar to array expression\n                // Currently don't support rest and default params\n                case 'ArrayPattern':\n                    for (let i = 0; i < nd.elements.length; i++) {\n                        // Array destructuring can ignore some values, so check null first\n                        if (nd.elements[i])\n                            flow_graph.addEdge(\n                                propVertex({ type: 'Literal', value: i }),\n                                vertexFor(nd.elements[i])\n                            );\n                    }\n                    break;\n\n                case 'MethodDefinition':\n                    if (nd.key.type === 'Identifier')\n                        flow_graph.addEdge(funcVertex(nd.value), propVertex(nd.key))\n                    break;\n\n                case 'WithStatement':\n                    // throw new Error(\"'with' statement not supported\");\n            }\n        });\n        return flow_graph;\n    }\n\n    /* Return the flow graph vertex corresponding to a given AST node. */\n    function vertexFor(nd) {\n        var decl, body;\n        switch (nd.type) {\n            case 'Identifier':\n                // global variables use a global vertex, local variables a var vertex\n                if (!nd.attr.scope)\n                    debugger;\n                decl = nd.attr.scope.get(nd.name);\n                return decl && !decl.attr.scope.global ? varVertex(decl) : globVertex(nd);\n            case 'ThisExpression':\n                // 'this' is treated like a variable\n                decl = nd.attr.scope.get('this');\n                return decl ? varVertex(decl) : exprVertex(nd);\n            case 'ClassExpression':\n                if (nd.id)\n                  return vertexFor(nd.id);\n\n                body = nd.body.body;\n                for (let i = 0; i < body.length; ++i)\n                    if (body[i].kind === 'constructor')\n                        return funcVertex(body[i].value);\n                break;\n            case 'MemberExpression':\n                // ignore dynamic property accesses\n                if (!nd.computed)\n                    return propVertex(nd.property);\n        }\n        return exprVertex(nd);\n    }\n\n    // variable vertices are cached at the variable declarations\n    function varVertex(nd) {\n        if (nd.type !== 'Identifier')\n            throw new Error(\"invalid variable vertex\");\n\n        return nd.attr.var_vertex\n            || (nd.attr.var_vertex = {\n            type: 'VarVertex',\n            node: nd,\n            attr: { pp: function () {\n                return 'Var(' + nd.name + ', ' + astutil.ppPos(nd) + ')';\n            } }\n        });\n    }\n\n    // global cache of property vertices\n    var propVertices = new symtab.Symtab();\n\n    // retrieve property vertex from cache, or create new one\n    function propVertex(nd) {\n        var p;\n        if (nd.type === 'Identifier')\n            p = nd.name;\n        else if (nd.type === 'Literal')\n            // this case handles array, property field: 0, 1, 2...\n            p = nd.value + \"\";\n        else\n            throw new Error(\"invalid property vertex\");\n\n        return propVertices.get(p, {\n            type: 'PropertyVertex',\n            name: p,\n            attr: {\n                pp: function () { return 'Prop(' + p + ')'; }\n            }\n        });\n    }\n\n    // global cache of global vertices\n    let globVertices = new symtab.Symtab();\n\n    // globVertices are propVertices in the global scope\n    // similar to propVertex, globVertex doesn't have an associated ast node\n    function globVertex(nd) {\n        let gp;\n        if (nd.type === 'Identifier')\n            gp = nd.name;\n        else if (nd.type === 'Literal')\n            // this case handles array, property field: 0, 1, 2...\n            gp = nd.value + \"\";\n        else\n            throw new Error(\"invalid global vertex\");\n\n        return globVertices.get(gp, {\n            type: 'GlobalVertex',\n            name: gp,\n            attr: {\n                pp: function () { return 'Glob(' + gp + ')'; }\n            }\n        });\n    }\n\n    // vertices representing well-known native functions\n    var nativeVertices = new symtab.Symtab();\n\n    function nativeVertex(name) {\n        return nativeVertices.get(name, { type: 'NativeVertex',\n            name: name,\n            attr: { pp: function () {\n                return name;\n            } } });\n    }\n\n    function getNativeVertices() {\n        return nativeVertices.values();\n    }\n\n    // special ``unknown'' vertex representing flow that is not explicitly modelled\n    var theUnknownVertex = { type: 'UnknownVertex',\n        attr: { pp: function () {\n            return 'Unknown';\n        } } };\n\n    function unknownVertex() {\n        return theUnknownVertex;\n    }\n\n    // function vertex\n    function funcVertex(fn) {\n        if (!astutil.isFunction(fn))\n            throw new Error(\"invalid function vertex\");\n        return fn.attr.func_vertex\n            || (fn.attr.func_vertex = {\n            type: 'FuncVertex',\n            func: fn,\n            attr: { pp: function () {\n                return 'Func(' + astutil.ppPos(fn) + ')';\n            } }\n        });\n    }\n\n    // parameter vertex\n    function parmVertex(fn, i) {\n        if (!astutil.isFunction(fn))\n            throw new Error(\"invalid function vertex\");\n        var vertex;\n        if (i === 0) {\n            vertex = varVertex(fn.attr.scope.get('this'));\n        } else {\n            // In ES6, fn.params[i - 1] might not be an Identifier\n            // vertex = varVertex(fn.params[i - 1]);\n            vertex = vertexFor(fn.params[i - 1]);\n        }\n        return vertex;\n    }\n\n    // vertex representing function return value\n    function retVertex(fn) {\n        if (!astutil.isFunction(fn))\n            throw new Error(\"invalid return vertex\");\n\n        return fn.attr.ret_vertex\n            || (fn.attr.ret_vertex = {\n            type: 'ReturnVertex',\n            node: fn,\n            attr: { pp: function () {\n                return 'Ret(' + astutil.ppPos(fn) + ')';\n            } }\n        });\n    }\n\n    // vertex representing callee at a call site\n    function calleeVertex(nd) {\n        if (nd.type !== 'CallExpression' && nd.type !== 'NewExpression')\n            throw new Error(\"invalid callee vertex\");\n\n        return nd.attr.callee_vertex\n            || (nd.attr.callee_vertex = {\n            type: 'CalleeVertex',\n            call: nd,\n            attr: { pp: function () {\n                return 'Callee(' + astutil.ppPos(nd) + ')';\n            } }\n        });\n    }\n\n    // vertex representing the ith argument at a call site; 0th argument is receiver\n    function argVertex(nd, i) {\n        if (nd.type !== 'CallExpression' && nd.type !== 'NewExpression')\n            throw new Error(\"invalid callee vertex\");\n        if (i === 0) {\n            return nd.attr.receiver_vertex\n                || (nd.attr.receiver_vertex = {\n                type: 'ArgumentVertex',\n                node: nd,\n                attr: { pp: function () {\n                    return 'Arg(' + astutil.ppPos(nd) + ', 0)';\n                } }\n            });\n        } else {\n            return nd.arguments[i - 1].attr.arg_vertex\n                || (nd.arguments[i - 1].attr.arg_vertex = {\n                type: 'ArgumentVertex',\n                node: nd,\n                attr: { pp: function () {\n                    return 'Arg(' + astutil.ppPos(nd) + ', ' + i + ')';\n                } }\n            });\n        }\n    }\n\n    // vertex representing result of a call\n    function resVertex(nd) {\n        if (nd.type !== 'CallExpression' && nd.type !== 'NewExpression')\n            throw new Error(\"invalid result vertex\");\n        return nd.attr.res_vertex\n            || (nd.attr.res_vertex = {\n            type: 'ResVertex',\n            node: nd,\n            attr: { pp: function () {\n                return 'Res(' + astutil.ppPos(nd) + ')';\n            } }\n        });\n    }\n\n    // vertex representing some other expression\n    function exprVertex(nd) {\n        if (!nd.type)\n            throw new Error(\"invalid expression vertex\");\n        return nd.attr.expr_vertex\n            || (nd.attr.expr_vertex = {\n            type: 'ExprVertex',\n            node: nd,\n            attr: { pp: function () {\n                return 'Expr(' + astutil.ppPos(nd) + ')';\n            } }\n        });\n    }\n\n    exports.addIntraproceduralFlowGraphEdges = addIntraproceduralFlowGraphEdges;\n    exports.funcVertex = funcVertex;\n    exports.unknownVertex = unknownVertex;\n    exports.globVertex = globVertex;\n    exports.nativeVertex = nativeVertex;\n    exports.getNativeVertices = getNativeVertices;\n    exports.parmVertex = parmVertex;\n    exports.argVertex = argVertex;\n    exports.retVertex = retVertex;\n    exports.resVertex = resVertex;\n    exports.vertexFor = vertexFor;\n    exports.propVertex = propVertex;\n    return exports;\n});\n"
  },
  {
    "path": "src/graph.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n /* Graphs represented using adjacency sets. */\n if (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    const { LinkedList } = require('./linkedList');\n\n    class BasicGraph {\n        constructor() {\n           this._pred = {};\n           this._succ = {};\n        }\n\n        addNode(node) {\n            this._pred[node] = this.pred(node);\n            this._succ[node] = this.succ(node);\n        }\n\n        // Remove all associated edges\n        // Does nothing if the node doesn not exist\n        removeNode(node) {\n            if (this._pred[node]) {\n                for (let p of this._pred[node]) {\n                    this._succ[p].remove(node);\n                }\n                delete this._pred[node];\n            }\n            if (this._succ[node]) {\n                for (let s of this._succ[node]) {\n                    this._pred[s].remove(node);\n                }\n                delete this._succ[node];\n            }\n        }\n\n        pred(node) {\n           return this._pred[node] || new LinkedList();\n        }\n\n        succ(node) {\n            return this._succ[node] || new LinkedList();\n        }\n\n        addEdge(u, v) {\n            this.addNode(u);\n            this.addNode(v);\n            this._succ[u].add(v);\n            this._pred[v].add(u);\n        }\n\n        // Does not remove the nodes\n        // Does nothing if the edge does not exist\n        removeEdge(u, v) {\n            if (this._succ[u]) {\n                this._succ[u].remove(v);\n            }\n            if (this._pred[v]) {\n                this._pred[v].remove(u);\n            }\n        }\n\n        nodes() {\n            return Object.keys(this._pred);\n        }\n\n        serialize() {\n            let serialized = {\n                nodes: this.nodes().map((id) => {\n                    return {id: id};\n                }),\n                links: []\n            }\n\n            serialized.nodes.forEach((node) => {\n                let source = node.id;\n                for (let target of this._succ[source]) {\n                    serialized.links.push({\n                        source: source,\n                        target: target\n                    });\n                }\n            });\n            return serialized;\n        }\n    }\n\n    function nodeToString(nd) {\n        return nd.attr.pp();\n    }\n\n    var cf = nodeToString;\n\n    function Graph() {\n        this.graph = new BasicGraph();\n        this.node_pairings = {};\n        this.edge_annotations = {};\n    }\n\n    /* Adds the node to the graph if not already there */\n    Graph.prototype.addNode = function (nd) {\n        if (this.hasNode(nd))\n            return;\n\n        this.node_pairings[cf(nd)] = nd;\n        this.graph.addNode(cf(nd));\n    }\n\n    Graph.prototype.addEdge = function (from, to, annote) {\n        this.addNode(from);\n        this.addNode(to);\n\n        this.graph.addEdge(cf(from), cf(to));\n\n        if (annote !== undefined)\n            this.edge_annotations[cf(from) + ' -> ' + cf(to)] = annote;\n    };\n\n    Graph.prototype.addEdges = function (from, tos, annotations) {\n        for (var i = 0; i < tos.length; ++i)\n            if (annotations !== undefined)\n                this.addEdge(from, tos[i], annotations[i]);\n            else\n                this.addEdge(from, tos[i]);\n    };\n\n    Graph.prototype.iter = function (cb) {\n        const nodes = this.graph.nodes();\n        for (let u of nodes) {\n            for (let v of this.graph.succ(u)) {\n                let u_nd = this.node_pairings[u];\n                let v_nd = this.node_pairings[v];\n                cb(u_nd, v_nd);\n            }\n        }\n    };\n\n    Graph.prototype.hasEdge = function (from, to) {\n        return this.graph.succ(cf(from)).has(cf(to));\n    };\n\n    Graph.prototype.succ = function (nd) {\n        let succ = this.graph.succ(cf(nd));\n        let lst = [];\n        for (let s of succ)\n            lst.push(this.node_pairings[s])\n        return lst;\n    }\n\n    Graph.prototype.hasNode = function (nd) {\n        return cf(nd) in this.node_pairings;\n    }\n\n    /* Remove (from , to), return false if edge doesn't exist */\n    Graph.prototype.removeEdge = function (from, to) {\n        if (this.hasNode(from) && this.hasNode(to) && this.hasEdge(from, to)){\n            this.graph.removeEdge(cf(from), cf(to))\n            return true;\n        }\n        return false;\n    };\n\n    /* Remove a node and all associated edges from graph */\n    Graph.prototype.removeNode = function (nd) {\n        if (this.hasNode(nd)) {\n            this.graph.removeNode(cf(nd));\n            delete this.node_pairings[cf(nd)];\n            return true;\n        }\n        return false;\n    };\n\n    Graph.prototype.iterNodes = function (cb) {\n        let nodes = this.graph.nodes();\n        for (let i = 0; i < nodes.length; i++) {\n            let cfn = nodes[i];\n            let n = this.node_pairings[cfn];\n            cb(n);\n        }\n    };\n\n    Graph.prototype.getNodes = function() {\n        let str_nodes = this.graph.nodes();\n        let nodes = [];\n        for (let i = 0; i < str_nodes.length; i++)\n            nodes.push(this.node_pairings[str_nodes[i]]);\n\n        return nodes;\n    };\n\n    /* Get enclosingFile of a node in flow graph by querying its associated AST node */\n    function getEnclosingFile (nd) {\n        if (nd.hasOwnProperty('node')) {\n            return nd.node.attr.enclosingFile;\n        } else if (nd.hasOwnProperty('call')) {\n            return nd.call.attr.enclosingFile;\n        } else if (nd.hasOwnProperty('func')) {\n            return nd.func.attr.enclosingFile;\n        } else {\n            // Native, Prop and Unknown vertices\n            return null;\n        }\n    }\n\n    class FlowGraph extends Graph {\n        constructor() {\n            super();\n            this._fileToNodes = {};\n        }\n\n        addEdge(from, to, annote) {\n            super.addEdge(from, to, annote);\n            this._updateFileToNodes(from);\n            this._updateFileToNodes(to);\n        }\n\n        _updateFileToNodes(fgNode) {\n            const enclosingFile = getEnclosingFile(fgNode);\n            if (enclosingFile === null)\n                return;\n            if (!(enclosingFile in this._fileToNodes))\n                this._fileToNodes[enclosingFile] = new Set();\n            this._fileToNodes[enclosingFile].add(fgNode);\n        }\n\n        removeNodesInFile(fileName) {\n            if (fileName in this._fileToNodes) {\n                for (let fgNode of this._fileToNodes[fileName]) {\n                    super.removeNode(fgNode);\n                }\n            }\n            else {\n                console.log(\"WARNING: fileName doesn't exist in _fileToNodes.\");\n            }\n        }\n    }\n\n\n    exports.Graph = Graph;\n    exports.FlowGraph = FlowGraph;\n    exports.nd2str = nodeToString;\n    return exports;\n});\n"
  },
  {
    "path": "src/harness.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* This module contains a list of native functions and the\n * properties they are originally stored in. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    // maps canonical name of native function to the property it is stored in\n    exports.nativeFlows = {\n        \"eval\": \"eval\",\n        \"parseInt\": \"parseInt\",\n        \"parseFloat\": \"parseFloat\",\n        \"isNaN\": \"isNaN\",\n        \"isFinite\": \"isFinite\",\n        \"decodeURI\": \"decodeURI\",\n        \"decodeURIComponent\": \"decodeURIComponent\",\n        \"encodeURI\": \"encodeURI\",\n        \"encodeURIComponent\": \"encodeURIComponent\",\n        \"Object\": \"Object\",\n        \"Object_defineProperties\": \"defineProperties\",\n        \"Object_isSealed\": \"isSealed\",\n        \"Object_defineProperty\": \"defineProperty\",\n        \"Object_freeze\": \"freeze\",\n        \"Object_preventExtensions\": \"preventExtensions\",\n        \"Object_keys\": \"keys\",\n        \"Object_getOwnPropertyNames\": \"getOwnPropertyNames\",\n        \"Object_getPrototypeOf\": \"getPrototypeOf\",\n        \"Object_is\": \"is\",\n        \"Object_isFrozen\": \"isFrozen\",\n        \"Object_prototype_toLocaleString\": \"toLocaleString\",\n        \"Object_prototype_valueOf\": \"valueOf\",\n        \"Object_prototype_toString\": \"toString\",\n        \"Object_prototype_hasOwnProperty\": \"hasOwnProperty\",\n        \"Object_prototype_isPrototypeOf\": \"isPrototypeOf\",\n        \"Object_prototype_propertyIsEnumerable\": \"propertyIsEnumerable\",\n        \"Object_getOwnPropertyDescriptor\": \"getOwnPropertyDescriptor\",\n        \"Object_isExtensible\": \"isExtensible\",\n        \"Object_seal\": \"seal\",\n        \"Object_create\": \"create\",\n        \"Function\": \"Function\",\n        \"Function_prototype\": \"prototype\",\n        \"Function_prototype_toString\": \"toString\",\n        \"Function_prototype_apply\": \"apply\",\n        \"Function_prototype_bind\": \"bind\",\n        \"Function_prototype_call\": \"call\",\n        \"Array\": \"Array\",\n        \"Array_isArray\": \"isArray\",\n        \"Array_prototype_some\": \"some\",\n        \"Array_prototype_indexOf\": \"indexOf\",\n        \"Array_prototype_lastIndexOf\": \"lastIndexOf\",\n        \"Array_prototype_push\": \"push\",\n        \"Array_prototype_sort\": \"sort\",\n        \"Array_prototype_concat\": \"concat\",\n        \"Array_prototype_toLocaleString\": \"toLocaleString\",\n        \"Array_prototype_map\": \"map\",\n        \"Array_prototype_forEach\": \"forEach\",\n        \"Array_prototype_splice\": \"splice\",\n        \"Array_prototype_reverse\": \"reverse\",\n        \"Array_prototype_toString\": \"toString\",\n        \"Array_prototype_join\": \"join\",\n        \"Array_prototype_every\": \"every\",\n        \"Array_prototype_slice\": \"slice\",\n        \"Array_prototype_reduce\": \"reduce\",\n        \"Array_prototype_pop\": \"pop\",\n        \"Array_prototype_unshift\": \"unshift\",\n        \"Array_prototype_shift\": \"shift\",\n        \"Array_prototype_reduceRight\": \"reduceRight\",\n        \"Array_prototype_filter\": \"filter\",\n        \"String\": \"String\",\n        \"String_prototype_strike\": \"strike\",\n        \"String_prototype_fontcolor\": \"fontcolor\",\n        \"String_prototype_blink\": \"blink\",\n        \"String_prototype_trimLeft\": \"trimLeft\",\n        \"String_prototype_fixed\": \"fixed\",\n        \"String_prototype_split\": \"split\",\n        \"String_prototype_indexOf\": \"indexOf\",\n        \"String_prototype_lastIndexOf\": \"lastIndexOf\",\n        \"String_prototype_charAt\": \"charAt\",\n        \"String_prototype_small\": \"small\",\n        \"String_prototype_toLocaleUpperCase\": \"toLocaleUpperCase\",\n        \"String_prototype_concat\": \"concat\",\n        \"String_prototype_bold\": \"bold\",\n        \"String_prototype_substring\": \"substring\",\n        \"String_prototype_toLowerCase\": \"toLowerCase\",\n        \"String_prototype_valueOf\": \"valueOf\",\n        \"String_prototype_big\": \"big\",\n        \"String_prototype_fontsize\": \"fontsize\",\n        \"String_prototype_italics\": \"italics\",\n        \"String_prototype_search\": \"search\",\n        \"String_prototype_sub\": \"sub\",\n        \"String_prototype_toString\": \"toString\",\n        \"String_prototype_toUpperCase\": \"toUpperCase\",\n        \"String_prototype_link\": \"link\",\n        \"String_prototype_slice\": \"slice\",\n        \"String_prototype_replace\": \"replace\",\n        \"String_prototype_anchor\": \"anchor\",\n        \"String_prototype_substr\": \"substr\",\n        \"String_prototype_localeCompare\": \"localeCompare\",\n        \"String_prototype_sup\": \"sup\",\n        \"String_prototype_charCodeAt\": \"charCodeAt\",\n        \"String_prototype_toLocaleLowerCase\": \"toLocaleLowerCase\",\n        \"String_prototype_trim\": \"trim\",\n        \"String_prototype_match\": \"match\",\n        \"String_prototype_trimRight\": \"trimRight\",\n        \"String_fromCharCode\": \"fromCharCode\",\n        \"Boolean\": \"Boolean\",\n        \"Boolean_prototype_valueOf\": \"valueOf\",\n        \"Boolean_prototype_toString\": \"toString\",\n        \"Number\": \"Number\",\n        \"Number_isFinite\": \"isFinite\",\n        \"Number_isNaN\": \"isNaN\",\n        \"Number_prototype_toFixed\": \"toFixed\",\n        \"Number_prototype_toExponential\": \"toExponential\",\n        \"Number_prototype_toLocaleString\": \"toLocaleString\",\n        \"Number_prototype_valueOf\": \"valueOf\",\n        \"Number_prototype_toString\": \"toString\",\n        \"Number_prototype_toPrecision\": \"toPrecision\",\n        \"Date\": \"Date\",\n        \"Date_now\": \"now\",\n        \"Date_UTC\": \"UTC\",\n        \"Date_parse\": \"parse\",\n        \"Date_prototype_getMinutes\": \"getMinutes\",\n        \"Date_prototype_setUTCMilliseconds\": \"setUTCMilliseconds\",\n        \"Date_prototype_setUTCDate\": \"setUTCDate\",\n        \"Date_prototype_getMonth\": \"getMonth\",\n        \"Date_prototype_toGMTString\": \"toGMTString\",\n        \"Date_prototype_setUTCMinutes\": \"setUTCMinutes\",\n        \"Date_prototype_setUTCMonth\": \"setUTCMonth\",\n        \"Date_prototype_getUTCMinutes\": \"getUTCMinutes\",\n        \"Date_prototype_setFullYear\": \"setFullYear\",\n        \"Date_prototype_toDateString\": \"toDateString\",\n        \"Date_prototype_getUTCDay\": \"getUTCDay\",\n        \"Date_prototype_getTimezoneOffset\": \"getTimezoneOffset\",\n        \"Date_prototype_setUTCHours\": \"setUTCHours\",\n        \"Date_prototype_getUTCDate\": \"getUTCDate\",\n        \"Date_prototype_getMilliseconds\": \"getMilliseconds\",\n        \"Date_prototype_getUTCMilliseconds\": \"getUTCMilliseconds\",\n        \"Date_prototype_getDay\": \"getDay\",\n        \"Date_prototype_toJSON\": \"toJSON\",\n        \"Date_prototype_getUTCFullYear\": \"getUTCFullYear\",\n        \"Date_prototype_toLocaleString\": \"toLocaleString\",\n        \"Date_prototype_setUTCSeconds\": \"setUTCSeconds\",\n        \"Date_prototype_setMonth\": \"setMonth\",\n        \"Date_prototype_getDate\": \"getDate\",\n        \"Date_prototype_valueOf\": \"valueOf\",\n        \"Date_prototype_setMinutes\": \"setMinutes\",\n        \"Date_prototype_getTime\": \"getTime\",\n        \"Date_prototype_setSeconds\": \"setSeconds\",\n        \"Date_prototype_toUTCString\": \"toUTCString\",\n        \"Date_prototype_setTime\": \"setTime\",\n        \"Date_prototype_toString\": \"toString\",\n        \"Date_prototype_setYear\": \"setYear\",\n        \"Date_prototype_setHours\": \"setHours\",\n        \"Date_prototype_toTimeString\": \"toTimeString\",\n        \"Date_prototype_getUTCSeconds\": \"getUTCSeconds\",\n        \"Date_prototype_toLocaleTimeString\": \"toLocaleTimeString\",\n        \"Date_prototype_setMilliseconds\": \"setMilliseconds\",\n        \"Date_prototype_getYear\": \"getYear\",\n        \"Date_prototype_getFullYear\": \"getFullYear\",\n        \"Date_prototype_getUTCMonth\": \"getUTCMonth\",\n        \"Date_prototype_getHours\": \"getHours\",\n        \"Date_prototype_toLocaleDateString\": \"toLocaleDateString\",\n        \"Date_prototype_getUTCHours\": \"getUTCHours\",\n        \"Date_prototype_toISOString\": \"toISOString\",\n        \"Date_prototype_getSeconds\": \"getSeconds\",\n        \"Date_prototype_setUTCFullYear\": \"setUTCFullYear\",\n        \"Date_prototype_setDate\": \"setDate\",\n        \"RegExp\": \"RegExp\",\n        \"RegExp_prototype_compile\": \"compile\",\n        \"RegExp_prototype_exec\": \"exec\",\n        \"RegExp_prototype_toString\": \"toString\",\n        \"RegExp_prototype_test\": \"test\",\n        \"Error\": \"Error\",\n        \"Error_captureStackTrace\": \"captureStackTrace\",\n        \"Error_prototype_toString\": \"toString\",\n        \"EvalError\": \"EvalError\",\n        \"RangeError\": \"RangeError\",\n        \"ReferenceError\": \"ReferenceError\",\n        \"SyntaxError\": \"SyntaxError\",\n        \"TypeError\": \"TypeError\",\n        \"URIError\": \"URIError\",\n        \"Math_sqrt\": \"sqrt\",\n        \"Math_abs\": \"abs\",\n        \"Math_max\": \"max\",\n        \"Math_tan\": \"tan\",\n        \"Math_round\": \"round\",\n        \"Math_random\": \"random\",\n        \"Math_exp\": \"exp\",\n        \"Math_log\": \"log\",\n        \"Math_ceil\": \"ceil\",\n        \"Math_sin\": \"sin\",\n        \"Math_atan\": \"atan\",\n        \"Math_cos\": \"cos\",\n        \"Math_asin\": \"asin\",\n        \"Math_pow\": \"pow\",\n        \"Math_atan2\": \"atan2\",\n        \"Math_acos\": \"acos\",\n        \"Math_min\": \"min\",\n        \"Math_floor\": \"floor\",\n        \"JSON_parse\": \"parse\",\n        \"JSON_stringify\": \"stringify\",\n        \"Attr\": \"Attr\",\n        \"Attr_toString\": \"toString\",\n        \"Audio\": \"Audio\",\n        \"DOMStringList\": \"DOMStringList\",\n        \"DOMStringList_toString\": \"toString\",\n        \"DOMStringList_prototype_contains\": \"contains\",\n        \"DOMStringList_prototype_item\": \"item\",\n        \"CanvasGradient\": \"CanvasGradient\",\n        \"CanvasGradient_toString\": \"toString\",\n        \"CanvasGradient_prototype_addColorStop\": \"addColorStop\",\n        \"CanvasPattern\": \"CanvasPattern\",\n        \"CanvasPattern_toString\": \"toString\",\n        \"CanvasRenderingContext2D\": \"CanvasRenderingContext2D\",\n        \"CanvasRenderingContext2D_toString\": \"toString\",\n        \"CanvasRenderingContext2D_prototype_fillRect\": \"fillRect\",\n        \"CanvasRenderingContext2D_prototype_setLineWidth\": \"setLineWidth\",\n        \"CanvasRenderingContext2D_prototype_save\": \"save\",\n        \"CanvasRenderingContext2D_prototype_strokeRect\": \"strokeRect\",\n        \"CanvasRenderingContext2D_prototype_createRadialGradient\": \"createRadialGradient\",\n        \"CanvasRenderingContext2D_prototype_stroke\": \"stroke\",\n        \"CanvasRenderingContext2D_prototype_setLineCap\": \"setLineCap\",\n        \"CanvasRenderingContext2D_prototype_isPointInPath\": \"isPointInPath\",\n        \"CanvasRenderingContext2D_prototype_lineTo\": \"lineTo\",\n        \"CanvasRenderingContext2D_prototype_setMiterLimit\": \"setMiterLimit\",\n        \"CanvasRenderingContext2D_prototype_clip\": \"clip\",\n        \"CanvasRenderingContext2D_prototype_arc\": \"arc\",\n        \"CanvasRenderingContext2D_prototype_closePath\": \"closePath\",\n        \"CanvasRenderingContext2D_prototype_restore\": \"restore\",\n        \"CanvasRenderingContext2D_prototype_getImageData\": \"getImageData\",\n        \"CanvasRenderingContext2D_prototype_setTransform\": \"setTransform\",\n        \"CanvasRenderingContext2D_prototype_setStrokeColor\": \"setStrokeColor\",\n        \"CanvasRenderingContext2D_prototype_clearRect\": \"clearRect\",\n        \"CanvasRenderingContext2D_prototype_webkitPutImageDataHD\": \"webkitPutImageDataHD\",\n        \"CanvasRenderingContext2D_prototype_setFillColor\": \"setFillColor\",\n        \"CanvasRenderingContext2D_prototype_createLinearGradient\": \"createLinearGradient\",\n        \"CanvasRenderingContext2D_prototype_drawImage\": \"drawImage\",\n        \"CanvasRenderingContext2D_prototype_bezierCurveTo\": \"bezierCurveTo\",\n        \"CanvasRenderingContext2D_prototype_moveTo\": \"moveTo\",\n        \"CanvasRenderingContext2D_prototype_fill\": \"fill\",\n        \"CanvasRenderingContext2D_prototype_rect\": \"rect\",\n        \"CanvasRenderingContext2D_prototype_webkitGetImageDataHD\": \"webkitGetImageDataHD\",\n        \"CanvasRenderingContext2D_prototype_fillText\": \"fillText\",\n        \"CanvasRenderingContext2D_prototype_putImageData\": \"putImageData\",\n        \"CanvasRenderingContext2D_prototype_beginPath\": \"beginPath\",\n        \"CanvasRenderingContext2D_prototype_rotate\": \"rotate\",\n        \"CanvasRenderingContext2D_prototype_measureText\": \"measureText\",\n        \"CanvasRenderingContext2D_prototype_scale\": \"scale\",\n        \"CanvasRenderingContext2D_prototype_quadraticCurveTo\": \"quadraticCurveTo\",\n        \"CanvasRenderingContext2D_prototype_translate\": \"translate\",\n        \"CanvasRenderingContext2D_prototype_setCompositeOperation\": \"setCompositeOperation\",\n        \"CanvasRenderingContext2D_prototype_clearShadow\": \"clearShadow\",\n        \"CanvasRenderingContext2D_prototype_setShadow\": \"setShadow\",\n        \"CanvasRenderingContext2D_prototype_setLineJoin\": \"setLineJoin\",\n        \"CanvasRenderingContext2D_prototype_arcTo\": \"arcTo\",\n        \"CanvasRenderingContext2D_prototype_strokeText\": \"strokeText\",\n        \"CanvasRenderingContext2D_prototype_createPattern\": \"createPattern\",\n        \"CanvasRenderingContext2D_prototype_drawImageFromRect\": \"drawImageFromRect\",\n        \"CanvasRenderingContext2D_prototype_transform\": \"transform\",\n        \"CanvasRenderingContext2D_prototype_setAlpha\": \"setAlpha\",\n        \"CanvasRenderingContext2D_prototype_createImageData\": \"createImageData\",\n        \"CDATASection\": \"CDATASection\",\n        \"CDATASection_toString\": \"toString\",\n        \"CharacterData\": \"CharacterData\",\n        \"CharacterData_toString\": \"toString\",\n        \"CharacterData_prototype_replaceData\": \"replaceData\",\n        \"CharacterData_prototype_insertData\": \"insertData\",\n        \"CharacterData_prototype_deleteData\": \"deleteData\",\n        \"CharacterData_prototype_appendData\": \"appendData\",\n        \"CharacterData_prototype_substringData\": \"substringData\",\n        \"Comment\": \"Comment\",\n        \"Comment_toString\": \"toString\",\n        \"CSSRule\": \"CSSRule\",\n        \"CSSRule_toString\": \"toString\",\n        \"CSSStyleDeclaration\": \"CSSStyleDeclaration\",\n        \"CSSStyleDeclaration_toString\": \"toString\",\n        \"CSSStyleDeclaration_prototype_getPropertyCSSValue\": \"getPropertyCSSValue\",\n        \"CSSStyleDeclaration_prototype_setProperty\": \"setProperty\",\n        \"CSSStyleDeclaration_prototype_getPropertyPriority\": \"getPropertyPriority\",\n        \"CSSStyleDeclaration_prototype_item\": \"item\",\n        \"CSSStyleDeclaration_prototype_isPropertyImplicit\": \"isPropertyImplicit\",\n        \"CSSStyleDeclaration_prototype_getPropertyValue\": \"getPropertyValue\",\n        \"CSSStyleDeclaration_prototype_getPropertyShorthand\": \"getPropertyShorthand\",\n        \"CSSStyleDeclaration_prototype_removeProperty\": \"removeProperty\",\n        \"CSSStyleSheet\": \"CSSStyleSheet\",\n        \"CSSStyleSheet_toString\": \"toString\",\n        \"CSSStyleSheet_prototype_deleteRule\": \"deleteRule\",\n        \"CSSStyleSheet_prototype_removeRule\": \"removeRule\",\n        \"CSSStyleSheet_prototype_insertRule\": \"insertRule\",\n        \"CSSStyleSheet_prototype_addRule\": \"addRule\",\n        \"Document\": \"Document\",\n        \"Document_toString\": \"toString\",\n        \"Document_prototype_createElementNS\": \"createElementNS\",\n        \"Document_prototype_queryCommandIndeterm\": \"queryCommandIndeterm\",\n        \"Document_prototype_createProcessingInstruction\": \"createProcessingInstruction\",\n        \"Document_prototype_evaluate\": \"evaluate\",\n        \"Document_prototype_createAttribute\": \"createAttribute\",\n        \"Document_prototype_adoptNode\": \"adoptNode\",\n        \"Document_prototype_getCSSCanvasContext\": \"getCSSCanvasContext\",\n        \"Document_prototype_createTextNode\": \"createTextNode\",\n        \"Document_prototype_queryCommandState\": \"queryCommandState\",\n        \"Document_prototype_importNode\": \"importNode\",\n        \"Document_prototype_getSelection\": \"getSelection\",\n        \"Document_prototype_webkitCancelFullScreen\": \"webkitCancelFullScreen\",\n        \"Document_prototype_createElement\": \"createElement\",\n        \"Document_prototype_getElementsByName\": \"getElementsByName\",\n        \"Document_prototype_createCDATASection\": \"createCDATASection\",\n        \"Document_prototype_querySelectorAll\": \"querySelectorAll\",\n        \"Document_prototype_caretRangeFromPoint\": \"caretRangeFromPoint\",\n        \"Document_prototype_queryCommandEnabled\": \"queryCommandEnabled\",\n        \"Document_prototype_createRange\": \"createRange\",\n        \"Document_prototype_createDocumentFragment\": \"createDocumentFragment\",\n        \"Document_prototype_createNodeIterator\": \"createNodeIterator\",\n        \"Document_prototype_createEntityReference\": \"createEntityReference\",\n        \"Document_prototype_createAttributeNS\": \"createAttributeNS\",\n        \"Document_prototype_getOverrideStyle\": \"getOverrideStyle\",\n        \"Document_prototype_execCommand\": \"execCommand\",\n        \"Document_prototype_createTreeWalker\": \"createTreeWalker\",\n        \"Document_prototype_getElementById\": \"getElementById\",\n        \"Document_prototype_webkitGetFlowByName\": \"webkitGetFlowByName\",\n        \"Document_prototype_getElementsByClassName\": \"getElementsByClassName\",\n        \"Document_prototype_querySelector\": \"querySelector\",\n        \"Document_prototype_createExpression\": \"createExpression\",\n        \"Document_prototype_createComment\": \"createComment\",\n        \"Document_prototype_createEvent\": \"createEvent\",\n        \"Document_prototype_elementFromPoint\": \"elementFromPoint\",\n        \"Document_prototype_getElementsByTagNameNS\": \"getElementsByTagNameNS\",\n        \"Document_prototype_createNSResolver\": \"createNSResolver\",\n        \"Document_prototype_webkitExitFullscreen\": \"webkitExitFullscreen\",\n        \"Document_prototype_queryCommandValue\": \"queryCommandValue\",\n        \"Document_prototype_getElementsByTagName\": \"getElementsByTagName\",\n        \"Document_prototype_queryCommandSupported\": \"queryCommandSupported\",\n        \"DocumentFragment\": \"DocumentFragment\",\n        \"DocumentFragment_toString\": \"toString\",\n        \"DocumentFragment_prototype_querySelectorAll\": \"querySelectorAll\",\n        \"DocumentFragment_prototype_querySelector\": \"querySelector\",\n        \"DocumentType\": \"DocumentType\",\n        \"DocumentType_toString\": \"toString\",\n        \"DOMException\": \"DOMException\",\n        \"DOMException_toString\": \"toString\",\n        \"DOMException_prototype_toString\": \"toString\",\n        \"DOMImplementation\": \"DOMImplementation\",\n        \"DOMImplementation_toString\": \"toString\",\n        \"DOMImplementation_prototype_createDocument\": \"createDocument\",\n        \"DOMImplementation_prototype_createHTMLDocument\": \"createHTMLDocument\",\n        \"DOMImplementation_prototype_createDocumentType\": \"createDocumentType\",\n        \"DOMImplementation_prototype_hasFeature\": \"hasFeature\",\n        \"DOMImplementation_prototype_createCSSStyleSheet\": \"createCSSStyleSheet\",\n        \"DOMParser\": \"DOMParser\",\n        \"DOMParser_toString\": \"toString\",\n        \"DOMParser_prototype_parseFromString\": \"parseFromString\",\n        \"Element\": \"Element\",\n        \"Element_toString\": \"toString\",\n        \"Element_prototype_setAttributeNode\": \"setAttributeNode\",\n        \"Element_prototype_scrollIntoView\": \"scrollIntoView\",\n        \"Element_prototype_webkitRequestFullScreen\": \"webkitRequestFullScreen\",\n        \"Element_prototype_getAttributeNode\": \"getAttributeNode\",\n        \"Element_prototype_focus\": \"focus\",\n        \"Element_prototype_setAttributeNS\": \"setAttributeNS\",\n        \"Element_prototype_getAttribute\": \"getAttribute\",\n        \"Element_prototype_scrollIntoViewIfNeeded\": \"scrollIntoViewIfNeeded\",\n        \"Element_prototype_hasAttributeNS\": \"hasAttributeNS\",\n        \"Element_prototype_getClientRects\": \"getClientRects\",\n        \"Element_prototype_getAttributeNS\": \"getAttributeNS\",\n        \"Element_prototype_webkitMatchesSelector\": \"webkitMatchesSelector\",\n        \"Element_prototype_setAttribute\": \"setAttribute\",\n        \"Element_prototype_removeAttributeNS\": \"removeAttributeNS\",\n        \"Element_prototype_getBoundingClientRect\": \"getBoundingClientRect\",\n        \"Element_prototype_querySelectorAll\": \"querySelectorAll\",\n        \"Element_prototype_hasAttribute\": \"hasAttribute\",\n        \"Element_prototype_setAttributeNodeNS\": \"setAttributeNodeNS\",\n        \"Element_prototype_getElementsByClassName\": \"getElementsByClassName\",\n        \"Element_prototype_getAttributeNodeNS\": \"getAttributeNodeNS\",\n        \"Element_prototype_querySelector\": \"querySelector\",\n        \"Element_prototype_webkitRequestFullscreen\": \"webkitRequestFullscreen\",\n        \"Element_prototype_removeAttribute\": \"removeAttribute\",\n        \"Element_prototype_scrollByLines\": \"scrollByLines\",\n        \"Element_prototype_blur\": \"blur\",\n        \"Element_prototype_removeAttributeNode\": \"removeAttributeNode\",\n        \"Element_prototype_getElementsByTagNameNS\": \"getElementsByTagNameNS\",\n        \"Element_prototype_scrollByPages\": \"scrollByPages\",\n        \"Element_prototype_getElementsByTagName\": \"getElementsByTagName\",\n        \"Event\": \"Event\",\n        \"Event_toString\": \"toString\",\n        \"Event_prototype_stopPropagation\": \"stopPropagation\",\n        \"Event_prototype_initEvent\": \"initEvent\",\n        \"Event_prototype_preventDefault\": \"preventDefault\",\n        \"Event_prototype_stopImmediatePropagation\": \"stopImmediatePropagation\",\n        \"HTMLCollection\": \"HTMLCollection\",\n        \"HTMLCollection_toString\": \"toString\",\n        \"HTMLCollection_prototype_item\": \"item\",\n        \"HTMLCollection_prototype_namedItem\": \"namedItem\",\n        \"HTMLElement\": \"HTMLElement\",\n        \"HTMLElement_toString\": \"toString\",\n        \"HTMLElement_prototype_click\": \"click\",\n        \"HTMLElement_prototype_insertAdjacentElement\": \"insertAdjacentElement\",\n        \"HTMLElement_prototype_insertAdjacentHTML\": \"insertAdjacentHTML\",\n        \"HTMLElement_prototype_insertAdjacentText\": \"insertAdjacentText\",\n        \"HTMLAnchorElement\": \"HTMLAnchorElement\",\n        \"HTMLAnchorElement_toString\": \"toString\",\n        \"HTMLAnchorElement_prototype_toString\": \"toString\",\n        \"HTMLAppletElement\": \"HTMLAppletElement\",\n        \"HTMLAppletElement_toString\": \"toString\",\n        \"HTMLAudioElement\": \"HTMLAudioElement\",\n        \"HTMLAudioElement_toString\": \"toString\",\n        \"HTMLAreaElement\": \"HTMLAreaElement\",\n        \"HTMLAreaElement_toString\": \"toString\",\n        \"HTMLBaseElement\": \"HTMLBaseElement\",\n        \"HTMLBaseElement_toString\": \"toString\",\n        \"HTMLBaseFontElement\": \"HTMLBaseFontElement\",\n        \"HTMLBaseFontElement_toString\": \"toString\",\n        \"HTMLBodyElement\": \"HTMLBodyElement\",\n        \"HTMLBodyElement_toString\": \"toString\",\n        \"HTMLBRElement\": \"HTMLBRElement\",\n        \"HTMLBRElement_toString\": \"toString\",\n        \"HTMLButtonElement\": \"HTMLButtonElement\",\n        \"HTMLButtonElement_toString\": \"toString\",\n        \"HTMLButtonElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLButtonElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLCanvasElement\": \"HTMLCanvasElement\",\n        \"HTMLCanvasElement_toString\": \"toString\",\n        \"HTMLCanvasElement_prototype_toDataURL\": \"toDataURL\",\n        \"HTMLCanvasElement_prototype_getContext\": \"getContext\",\n        \"HTMLDirectoryElement\": \"HTMLDirectoryElement\",\n        \"HTMLDirectoryElement_toString\": \"toString\",\n        \"HTMLDivElement\": \"HTMLDivElement\",\n        \"HTMLDivElement_toString\": \"toString\",\n        \"HTMLDListElement\": \"HTMLDListElement\",\n        \"HTMLDListElement_toString\": \"toString\",\n        \"HTMLEmbedElement\": \"HTMLEmbedElement\",\n        \"HTMLEmbedElement_toString\": \"toString\",\n        \"HTMLEmbedElement_prototype_getSVGDocument\": \"getSVGDocument\",\n        \"HTMLFieldSetElement\": \"HTMLFieldSetElement\",\n        \"HTMLFieldSetElement_toString\": \"toString\",\n        \"HTMLFieldSetElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLFieldSetElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLFontElement\": \"HTMLFontElement\",\n        \"HTMLFontElement_toString\": \"toString\",\n        \"HTMLFormElement\": \"HTMLFormElement\",\n        \"HTMLFormElement_toString\": \"toString\",\n        \"HTMLFormElement_prototype_reset\": \"reset\",\n        \"HTMLFormElement_prototype_submit\": \"submit\",\n        \"HTMLFormElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLFrameElement\": \"HTMLFrameElement\",\n        \"HTMLFrameElement_toString\": \"toString\",\n        \"HTMLFrameElement_prototype_getSVGDocument\": \"getSVGDocument\",\n        \"HTMLFrameSetElement\": \"HTMLFrameSetElement\",\n        \"HTMLFrameSetElement_toString\": \"toString\",\n        \"HTMLHeadElement\": \"HTMLHeadElement\",\n        \"HTMLHeadElement_toString\": \"toString\",\n        \"HTMLHeadingElement\": \"HTMLHeadingElement\",\n        \"HTMLHeadingElement_toString\": \"toString\",\n        \"HTMLHtmlElement\": \"HTMLHtmlElement\",\n        \"HTMLHtmlElement_toString\": \"toString\",\n        \"HTMLHRElement\": \"HTMLHRElement\",\n        \"HTMLHRElement_toString\": \"toString\",\n        \"HTMLIFrameElement\": \"HTMLIFrameElement\",\n        \"HTMLIFrameElement_toString\": \"toString\",\n        \"HTMLIFrameElement_prototype_getSVGDocument\": \"getSVGDocument\",\n        \"HTMLImageElement\": \"HTMLImageElement\",\n        \"HTMLImageElement_toString\": \"toString\",\n        \"HTMLInputElement\": \"HTMLInputElement\",\n        \"HTMLInputElement_toString\": \"toString\",\n        \"HTMLInputElement_prototype_stepDown\": \"stepDown\",\n        \"HTMLInputElement_prototype_select\": \"select\",\n        \"HTMLInputElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLInputElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLInputElement_prototype_setSelectionRange\": \"setSelectionRange\",\n        \"HTMLInputElement_prototype_stepUp\": \"stepUp\",\n        \"HTMLKeygenElement\": \"HTMLKeygenElement\",\n        \"HTMLKeygenElement_toString\": \"toString\",\n        \"HTMLKeygenElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLKeygenElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLLabelElement\": \"HTMLLabelElement\",\n        \"HTMLLabelElement_toString\": \"toString\",\n        \"HTMLLIElement\": \"HTMLLIElement\",\n        \"HTMLLIElement_toString\": \"toString\",\n        \"HTMLLinkElement\": \"HTMLLinkElement\",\n        \"HTMLLinkElement_toString\": \"toString\",\n        \"HTMLMapElement\": \"HTMLMapElement\",\n        \"HTMLMapElement_toString\": \"toString\",\n        \"HTMLMenuElement\": \"HTMLMenuElement\",\n        \"HTMLMenuElement_toString\": \"toString\",\n        \"HTMLMetaElement\": \"HTMLMetaElement\",\n        \"HTMLMetaElement_toString\": \"toString\",\n        \"HTMLModElement\": \"HTMLModElement\",\n        \"HTMLModElement_toString\": \"toString\",\n        \"HTMLObjectElement\": \"HTMLObjectElement\",\n        \"HTMLObjectElement_toString\": \"toString\",\n        \"HTMLObjectElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLObjectElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLObjectElement_prototype_getSVGDocument\": \"getSVGDocument\",\n        \"HTMLOListElement\": \"HTMLOListElement\",\n        \"HTMLOListElement_toString\": \"toString\",\n        \"HTMLOptGroupElement\": \"HTMLOptGroupElement\",\n        \"HTMLOptGroupElement_toString\": \"toString\",\n        \"HTMLOptionElement\": \"HTMLOptionElement\",\n        \"HTMLOptionElement_toString\": \"toString\",\n        \"HTMLOutputElement\": \"HTMLOutputElement\",\n        \"HTMLOutputElement_toString\": \"toString\",\n        \"HTMLOutputElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLOutputElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLParagraphElement\": \"HTMLParagraphElement\",\n        \"HTMLParagraphElement_toString\": \"toString\",\n        \"HTMLParamElement\": \"HTMLParamElement\",\n        \"HTMLParamElement_toString\": \"toString\",\n        \"HTMLPreElement\": \"HTMLPreElement\",\n        \"HTMLPreElement_toString\": \"toString\",\n        \"HTMLQuoteElement\": \"HTMLQuoteElement\",\n        \"HTMLQuoteElement_toString\": \"toString\",\n        \"HTMLScriptElement\": \"HTMLScriptElement\",\n        \"HTMLScriptElement_toString\": \"toString\",\n        \"HTMLSelectElement\": \"HTMLSelectElement\",\n        \"HTMLSelectElement_toString\": \"toString\",\n        \"HTMLSelectElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLSelectElement_prototype_add\": \"add\",\n        \"HTMLSelectElement_prototype_item\": \"item\",\n        \"HTMLSelectElement_prototype_namedItem\": \"namedItem\",\n        \"HTMLSelectElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLSelectElement_prototype_remove\": \"remove\",\n        \"HTMLSourceElement\": \"HTMLSourceElement\",\n        \"HTMLSourceElement_toString\": \"toString\",\n        \"HTMLSpanElement\": \"HTMLSpanElement\",\n        \"HTMLSpanElement_toString\": \"toString\",\n        \"HTMLStyleElement\": \"HTMLStyleElement\",\n        \"HTMLStyleElement_toString\": \"toString\",\n        \"HTMLTableElement\": \"HTMLTableElement\",\n        \"HTMLTableElement_toString\": \"toString\",\n        \"HTMLTableElement_prototype_deleteTFoot\": \"deleteTFoot\",\n        \"HTMLTableElement_prototype_deleteRow\": \"deleteRow\",\n        \"HTMLTableElement_prototype_createTHead\": \"createTHead\",\n        \"HTMLTableElement_prototype_createTFoot\": \"createTFoot\",\n        \"HTMLTableElement_prototype_createTBody\": \"createTBody\",\n        \"HTMLTableElement_prototype_deleteTHead\": \"deleteTHead\",\n        \"HTMLTableElement_prototype_createCaption\": \"createCaption\",\n        \"HTMLTableElement_prototype_insertRow\": \"insertRow\",\n        \"HTMLTableElement_prototype_deleteCaption\": \"deleteCaption\",\n        \"HTMLTableCaptionElement\": \"HTMLTableCaptionElement\",\n        \"HTMLTableCaptionElement_toString\": \"toString\",\n        \"HTMLTableColElement\": \"HTMLTableColElement\",\n        \"HTMLTableColElement_toString\": \"toString\",\n        \"HTMLTableRowElement\": \"HTMLTableRowElement\",\n        \"HTMLTableRowElement_toString\": \"toString\",\n        \"HTMLTableRowElement_prototype_insertCell\": \"insertCell\",\n        \"HTMLTableRowElement_prototype_deleteCell\": \"deleteCell\",\n        \"HTMLTableSectionElement\": \"HTMLTableSectionElement\",\n        \"HTMLTableSectionElement_toString\": \"toString\",\n        \"HTMLTableSectionElement_prototype_deleteRow\": \"deleteRow\",\n        \"HTMLTableSectionElement_prototype_insertRow\": \"insertRow\",\n        \"HTMLTextAreaElement\": \"HTMLTextAreaElement\",\n        \"HTMLTextAreaElement_toString\": \"toString\",\n        \"HTMLTextAreaElement_prototype_select\": \"select\",\n        \"HTMLTextAreaElement_prototype_setCustomValidity\": \"setCustomValidity\",\n        \"HTMLTextAreaElement_prototype_checkValidity\": \"checkValidity\",\n        \"HTMLTextAreaElement_prototype_setSelectionRange\": \"setSelectionRange\",\n        \"HTMLTitleElement\": \"HTMLTitleElement\",\n        \"HTMLTitleElement_toString\": \"toString\",\n        \"HTMLUListElement\": \"HTMLUListElement\",\n        \"HTMLUListElement_toString\": \"toString\",\n        \"HTMLUnknownElement\": \"HTMLUnknownElement\",\n        \"HTMLUnknownElement_toString\": \"toString\",\n        \"HTMLVideoElement\": \"HTMLVideoElement\",\n        \"HTMLVideoElement_toString\": \"toString\",\n        \"HTMLVideoElement_prototype_webkitEnterFullscreen\": \"webkitEnterFullscreen\",\n        \"HTMLVideoElement_prototype_webkitEnterFullScreen\": \"webkitEnterFullScreen\",\n        \"HTMLVideoElement_prototype_webkitExitFullScreen\": \"webkitExitFullScreen\",\n        \"HTMLVideoElement_prototype_webkitExitFullscreen\": \"webkitExitFullscreen\",\n        \"Image\": \"Image\",\n        \"ImageData\": \"ImageData\",\n        \"ImageData_toString\": \"toString\",\n        \"MimeType\": \"MimeType\",\n        \"MimeType_toString\": \"toString\",\n        \"MouseEvent\": \"MouseEvent\",\n        \"MouseEvent_toString\": \"toString\",\n        \"MouseEvent_prototype_initMouseEvent\": \"initMouseEvent\",\n        \"Node\": \"Node\",\n        \"Node_toString\": \"toString\",\n        \"Node_prototype_insertBefore\": \"insertBefore\",\n        \"Node_prototype_addEventListener\": \"addEventListener\",\n        \"Node_prototype_compareDocumentPosition\": \"compareDocumentPosition\",\n        \"Node_prototype_contains\": \"contains\",\n        \"Node_prototype_hasAttributes\": \"hasAttributes\",\n        \"Node_prototype_isSupported\": \"isSupported\",\n        \"Node_prototype_lookupNamespaceURI\": \"lookupNamespaceURI\",\n        \"Node_prototype_lookupPrefix\": \"lookupPrefix\",\n        \"Node_prototype_isSameNode\": \"isSameNode\",\n        \"Node_prototype_normalize\": \"normalize\",\n        \"Node_prototype_removeChild\": \"removeChild\",\n        \"Node_prototype_cloneNode\": \"cloneNode\",\n        \"Node_prototype_hasChildNodes\": \"hasChildNodes\",\n        \"Node_prototype_dispatchEvent\": \"dispatchEvent\",\n        \"Node_prototype_removeEventListener\": \"removeEventListener\",\n        \"Node_prototype_isDefaultNamespace\": \"isDefaultNamespace\",\n        \"Node_prototype_replaceChild\": \"replaceChild\",\n        \"Node_prototype_isEqualNode\": \"isEqualNode\",\n        \"Node_prototype_appendChild\": \"appendChild\",\n        \"NodeList\": \"NodeList\",\n        \"NodeList_toString\": \"toString\",\n        \"NodeList_prototype_item\": \"item\",\n        \"Option\": \"Option\",\n        \"Plugin\": \"Plugin\",\n        \"Plugin_toString\": \"toString\",\n        \"Plugin_prototype_item\": \"item\",\n        \"Plugin_prototype_namedItem\": \"namedItem\",\n        \"ProcessingInstruction\": \"ProcessingInstruction\",\n        \"ProcessingInstruction_toString\": \"toString\",\n        \"Range\": \"Range\",\n        \"Range_toString\": \"toString\",\n        \"Range_prototype_setEnd\": \"setEnd\",\n        \"Range_prototype_compareNode\": \"compareNode\",\n        \"Range_prototype_intersectsNode\": \"intersectsNode\",\n        \"Range_prototype_isPointInRange\": \"isPointInRange\",\n        \"Range_prototype_getClientRects\": \"getClientRects\",\n        \"Range_prototype_setStartAfter\": \"setStartAfter\",\n        \"Range_prototype_insertNode\": \"insertNode\",\n        \"Range_prototype_extractContents\": \"extractContents\",\n        \"Range_prototype_expand\": \"expand\",\n        \"Range_prototype_deleteContents\": \"deleteContents\",\n        \"Range_prototype_getBoundingClientRect\": \"getBoundingClientRect\",\n        \"Range_prototype_setStartBefore\": \"setStartBefore\",\n        \"Range_prototype_compareBoundaryPoints\": \"compareBoundaryPoints\",\n        \"Range_prototype_cloneContents\": \"cloneContents\",\n        \"Range_prototype_toString\": \"toString\",\n        \"Range_prototype_createContextualFragment\": \"createContextualFragment\",\n        \"Range_prototype_selectNode\": \"selectNode\",\n        \"Range_prototype_collapse\": \"collapse\",\n        \"Range_prototype_setEndBefore\": \"setEndBefore\",\n        \"Range_prototype_detach\": \"detach\",\n        \"Range_prototype_setStart\": \"setStart\",\n        \"Range_prototype_comparePoint\": \"comparePoint\",\n        \"Range_prototype_selectNodeContents\": \"selectNodeContents\",\n        \"Range_prototype_cloneRange\": \"cloneRange\",\n        \"Range_prototype_setEndAfter\": \"setEndAfter\",\n        \"Range_prototype_surroundContents\": \"surroundContents\",\n        \"RangeException\": \"RangeException\",\n        \"RangeException_toString\": \"toString\",\n        \"RangeException_prototype_toString\": \"toString\",\n        \"Text\": \"Text\",\n        \"Text_toString\": \"toString\",\n        \"Text_prototype_splitText\": \"splitText\",\n        \"Text_prototype_replaceWholeText\": \"replaceWholeText\",\n        \"TextMetrics\": \"TextMetrics\",\n        \"TextMetrics_toString\": \"toString\",\n        \"UIEvent\": \"UIEvent\",\n        \"UIEvent_toString\": \"toString\",\n        \"UIEvent_prototype_initUIEvent\": \"initUIEvent\",\n        \"Window\": \"Window\",\n        \"Window_toString\": \"toString\",\n        \"Window_prototype_releaseEvents\": \"releaseEvents\",\n        \"Window_prototype_scrollBy\": \"scrollBy\",\n        \"Window_prototype_alert\": \"alert\",\n        \"Window_prototype_removeEventListener\": \"removeEventListener\",\n        \"Window_prototype_btoa\": \"btoa\",\n        \"Window_prototype_postMessage\": \"postMessage\",\n        \"Window_prototype_webkitRequestFileSystem\": \"webkitRequestFileSystem\",\n        \"Window_prototype_open\": \"open\",\n        \"Window_prototype_focus\": \"focus\",\n        \"Window_prototype_prompt\": \"prompt\",\n        \"Window_prototype_getMatchedCSSRules\": \"getMatchedCSSRules\",\n        \"Window_prototype_webkitCancelAnimationFrame\": \"webkitCancelAnimationFrame\",\n        \"Window_prototype_webkitConvertPointFromPageToNode\": \"webkitConvertPointFromPageToNode\",\n        \"Window_prototype_webkitPostMessage\": \"webkitPostMessage\",\n        \"Window_prototype_find\": \"find\",\n        \"Window_prototype_scroll\": \"scroll\",\n        \"Window_prototype_getSelection\": \"getSelection\",\n        \"Window_prototype_print\": \"print\",\n        \"Window_prototype_setInterval\": \"setInterval\",\n        \"Window_prototype_close\": \"close\",\n        \"Window_prototype_stop\": \"stop\",\n        \"Window_prototype_dispatchEvent\": \"dispatchEvent\",\n        \"Window_prototype_resizeBy\": \"resizeBy\",\n        \"Window_prototype_clearTimeout\": \"clearTimeout\",\n        \"Window_prototype_setTimeout\": \"setTimeout\",\n        \"Window_prototype_clearInterval\": \"clearInterval\",\n        \"Window_prototype_captureEvents\": \"captureEvents\",\n        \"Window_prototype_toString\": \"toString\",\n        \"Window_prototype_webkitConvertPointFromNodeToPage\": \"webkitConvertPointFromNodeToPage\",\n        \"Window_prototype_webkitCancelRequestAnimationFrame\": \"webkitCancelRequestAnimationFrame\",\n        \"Window_prototype_atob\": \"atob\",\n        \"Window_prototype_moveTo\": \"moveTo\",\n        \"Window_prototype_webkitResolveLocalFileSystemURL\": \"webkitResolveLocalFileSystemURL\",\n        \"Window_prototype_getComputedStyle\": \"getComputedStyle\",\n        \"Window_prototype_confirm\": \"confirm\",\n        \"Window_prototype_scrollTo\": \"scrollTo\",\n        \"Window_prototype_webkitRequestAnimationFrame\": \"webkitRequestAnimationFrame\",\n        \"Window_prototype_matchMedia\": \"matchMedia\",\n        \"Window_prototype_resizeTo\": \"resizeTo\",\n        \"Window_prototype_blur\": \"blur\",\n        \"Window_prototype_showModalDialog\": \"showModalDialog\",\n        \"Window_prototype_moveBy\": \"moveBy\",\n        \"Window_prototype_openDatabase\": \"openDatabase\",\n        \"Window_prototype_addEventListener\": \"addEventListener\",\n        \"XMLHttpRequest\": \"XMLHttpRequest\",\n        \"XMLHttpRequest_toString\": \"toString\",\n        \"XMLHttpRequest_prototype_getResponseHeader\": \"getResponseHeader\",\n        \"XMLHttpRequest_prototype_removeEventListener\": \"removeEventListener\",\n        \"XMLHttpRequest_prototype_open\": \"open\",\n        \"XMLHttpRequest_prototype_abort\": \"abort\",\n        \"XMLHttpRequest_prototype_setRequestHeader\": \"setRequestHeader\",\n        \"XMLHttpRequest_prototype_send\": \"send\",\n        \"XMLHttpRequest_prototype_dispatchEvent\": \"dispatchEvent\",\n        \"XMLHttpRequest_prototype_overrideMimeType\": \"overrideMimeType\",\n        \"XMLHttpRequest_prototype_getAllResponseHeaders\": \"getAllResponseHeaders\",\n        \"XMLHttpRequest_prototype_addEventListener\": \"addEventListener\",\n        \"XMLSerializer\": \"XMLSerializer\",\n        \"XMLSerializer_toString\": \"toString\",\n        \"XMLSerializer_prototype_serializeToString\": \"serializeToString\",\n        \"XPathResult\": \"XPathResult\",\n        \"XPathResult_toString\": \"toString\",\n        \"XPathResult_prototype_iterateNext\": \"iterateNext\",\n        \"XPathResult_prototype_snapshotItem\": \"snapshotItem\",\n        \"XSLTProcessor\": \"XSLTProcessor\",\n        \"XSLTProcessor_toString\": \"toString\",\n        \"XSLTProcessor_prototype_removeParameter\": \"removeParameter\",\n        \"XSLTProcessor_prototype_reset\": \"reset\",\n        \"XSLTProcessor_prototype_clearParameters\": \"clearParameters\",\n        \"XSLTProcessor_prototype_transformToFragment\": \"transformToFragment\",\n        \"XSLTProcessor_prototype_setParameter\": \"setParameter\",\n        \"XSLTProcessor_prototype_importStylesheet\": \"importStylesheet\",\n        \"XSLTProcessor_prototype_transformToDocument\": \"transformToDocument\",\n        \"XSLTProcessor_prototype_getParameter\": \"getParameter\",\n        \"ArrayBuffer\": \"ArrayBuffer\",\n        \"ArrayBuffer_toString\": \"toString\",\n        \"ArrayBuffer_prototype_slice\": \"slice\",\n        \"DataView\": \"DataView\",\n        \"DataView_toString\": \"toString\",\n        \"DataView_prototype_getUint16\": \"getUint16\",\n        \"DataView_prototype_setFloat32\": \"setFloat32\",\n        \"DataView_prototype_setInt16\": \"setInt16\",\n        \"DataView_prototype_getInt16\": \"getInt16\",\n        \"DataView_prototype_getInt8\": \"getInt8\",\n        \"DataView_prototype_getFloat32\": \"getFloat32\",\n        \"DataView_prototype_setUint8\": \"setUint8\",\n        \"DataView_prototype_setInt8\": \"setInt8\",\n        \"DataView_prototype_getUint8\": \"getUint8\",\n        \"DataView_prototype_setFloat64\": \"setFloat64\",\n        \"DataView_prototype_getFloat64\": \"getFloat64\",\n        \"DataView_prototype_getUint32\": \"getUint32\",\n        \"DataView_prototype_getInt32\": \"getInt32\",\n        \"DataView_prototype_setInt32\": \"setInt32\",\n        \"DataView_prototype_setUint16\": \"setUint16\",\n        \"DataView_prototype_setUint32\": \"setUint32\",\n        \"Float32Array\": \"Float32Array\",\n        \"Float32Array_toString\": \"toString\",\n        \"Float32Array_prototype_set\": \"set\",\n        \"Float32Array_prototype_subarray\": \"subarray\",\n        \"Float64Array\": \"Float64Array\",\n        \"Float64Array_toString\": \"toString\",\n        \"Float64Array_prototype_set\": \"set\",\n        \"Float64Array_prototype_subarray\": \"subarray\",\n        \"Int16Array\": \"Int16Array\",\n        \"Int16Array_toString\": \"toString\",\n        \"Int16Array_prototype_set\": \"set\",\n        \"Int16Array_prototype_subarray\": \"subarray\",\n        \"Int32Array\": \"Int32Array\",\n        \"Int32Array_toString\": \"toString\",\n        \"Int32Array_prototype_set\": \"set\",\n        \"Int32Array_prototype_subarray\": \"subarray\",\n        \"Int8Array\": \"Int8Array\",\n        \"Int8Array_toString\": \"toString\",\n        \"Int8Array_prototype_set\": \"set\",\n        \"Int8Array_prototype_subarray\": \"subarray\",\n        \"Uint16Array\": \"Uint16Array\",\n        \"Uint16Array_toString\": \"toString\",\n        \"Uint16Array_prototype_set\": \"set\",\n        \"Uint16Array_prototype_subarray\": \"subarray\",\n        \"Uint32Array\": \"Uint32Array\",\n        \"Uint32Array_toString\": \"toString\",\n        \"Uint32Array_prototype_set\": \"set\",\n        \"Uint32Array_prototype_subarray\": \"subarray\",\n        \"Uint8Array\": \"Uint8Array\",\n        \"Uint8Array_toString\": \"toString\",\n        \"Uint8Array_prototype_set\": \"set\",\n        \"Uint8Array_prototype_subarray\": \"subarray\",\n        \"console_log\": \"log\",\n        \"console_warn\": \"warn\",\n        \"console_error\": \"error\",\n        \"Audio_prototype_canPlayType\": \"canPlayType\",\n        \"Audio_prototype_load\": \"load\",\n        \"Audio_prototype_pause\": \"pause\",\n        \"Audio_prototype_play\": \"play\",\n        \"Node_prototype_attachEvent\": \"attachEvent\",\n        \"Node_prototype_detachEvent\": \"detachEvent\",\n        \"Node_prototype_doScroll\": \"doScroll\"\n    };\n\n    return exports;\n});\n"
  },
  {
    "path": "src/input-2.js",
    "content": "function aap() {\n    noot();\n}\n\nfunction noot() {\n    var mies = wim;\n    mies();\n}\n\nfunction wim() {\n    var output = zus(1, 2);\n}\n\nfunction zus(x, y) {\n    x + y;\n    jet(teun);\n    (function(num) { 1 + num; })(1);\n}\n\nfunction teun() {\n    1  - 1;\n}\n\nfunction jet(func) {\n    func();\n}"
  },
  {
    "path": "src/linkedList.js",
    "content": "\nclass ListNode {\n    constructor(ele) {\n        this._ele = ele;\n        this._next = null;\n    }\n\n    set next(value) {\n        this._next = value;\n    }\n\n    get next() {\n        return this._next;\n    }\n\n    get element() {\n        return this._ele;\n    }\n}\n\nclass LinkedList {\n    constructor() {\n        this._head = null;\n        this._size = 0;\n    }\n\n    // simply adds ele to the head of the list\n    add(ele) {\n        let lnode = new ListNode(ele);\n        lnode.next = this._head;\n        this._head = lnode;\n        this._size++;\n    }\n\n    // returns the removed element, or if its not found it returns -1\n    remove(ele) {\n        let current = this._head;\n        let prev = null;\n        while (current !== null) {\n            if (current.element === ele) {\n                if (prev === null) {\n                    this._head = current.next;\n                }\n                else {\n                    prev.next = current.next;\n                }\n                this._size--;\n                return current.element;\n            }\n            prev = current;\n            current = current.next;\n        }\n        return -1;\n    }\n\n    has(ele) {\n        let current = this._head;\n        while (current !== null) {\n            if (current.element === ele)\n                return true;\n            current = current.next;\n        }\n        return false;\n    }\n\n    isEmpty() {\n        return this._size === 0;\n    }\n\n    get size() {\n        return this._size;\n    }\n\n    [Symbol.iterator]() {\n        let value = null;\n        let current = this._head;\n        const iterator = {\n            next: () => {\n                if (current !== null) {\n                    value = current;\n                    current = current.next;\n                    return {value: value.element, done: false}\n                }\n                else {\n                    return {value: undefined, done: true};\n                }\n            }\n        }\n        return iterator;\n    }\n}\n\nmodule.exports.LinkedList = LinkedList;\n"
  },
  {
    "path": "src/module.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\nconst astutil = require('./astutil');\nconst flowgraph = require('./flowgraph');\nconst path = require('path');\n\n/* Export\n\nSyntax:\n    // Named\n    export { name1, name2, …, nameN };\n    export { variable1 as name1, variable2 as name2, …, nameN };\n    export let name1, name2, …, nameN; // also var, const\n    export let name1 = …, name2 = …, …, nameN; // also var, const\n    export function FunctionName(){...}\n    export class ClassName {...}\n\n    // Default\n    export default expression;\n    export default function (…) { … } // also class, function*\n    export default function name1(…) { … } // also class, function*\n    export { name1 as default, … };\n\n    // Redirect\n    export * from …;\n    export { name1, name2, …, nameN } from …;\n    export { import1 as name1, import2 as name2, …, nameN } from …;\n    export { default } from …;\n\nEsprima AST:\n\n    interface ExportAllDeclaration {\n        type: 'ExportAllDeclaration';\n        source: Literal;\n    }\n\n    interface ExportDefaultDeclaration {\n        type: 'ExportDefaultDeclaration';\n        declaration: Identifier | BindingPattern | ClassDeclaration | Expression | FunctionDeclaration;\n    }\n\n    interface ExportNamedDeclaration {\n        type: 'ExportNamedDeclaration';\n        declaration: ClassDeclaration | FunctionDeclaration | VariableDeclaration;\n        specifiers: ExportSpecifier[];\n        source: Literal;\n    }\n\n    with\n\n    interface ExportSpecifier {\n        type: 'ExportSpecifier';\n        exported: Identifier;\n        local: Identifier;\n    };\n*/\n\n/* Import\n\nSyntax:\n    import defaultExport from \"module-name\";\n    import * as name from \"module-name\";\n    import { export } from \"module-name\";\n    import { export as alias } from \"module-name\";\n    import { export1 , export2 } from \"module-name\";\n    import { export1 , export2 as alias2 , [...] } from \"module-name\";\n    import defaultExport, { export [ , [...] ] } from \"module-name\";\n    import defaultExport, * as name from \"module-name\";\n    import \"module-name\";\n    var promise = import(module-name);\n\nEsprima AST:\n\n    type ImportDeclaration {\n        type: 'ImportDeclaration';\n        specifiers: ImportSpecifier[];\n        source: Literal;\n    }\n\n    with\n\n    interface ImportSpecifier {\n        type: 'ImportSpecifier' | 'ImportDefaultSpecifier' | 'ImportNamespaceSpecifier';\n        local: Identifier;\n        imported?: Identifier;\n    }\n*/\n\n/* Create an entry in expFuncs for fname */\nfunction addFileToExports(expFuncs, fname) {\n    expFuncs[fname] = {\n        'default': [],\n        'named': {},\n        'redirect': []\n    };\n}\n\n/* Create an entry in impFuncs[fname] for srcFname*/\nfunction addSrcToFile(impFuncs, fname, srcFname) {\n    impFuncs[fname][srcFname] = {\n        'default': [],\n        'named': {},\n        'entire': false\n    };\n}\n\n/* Remove fname's entry in expFuncs */\nfunction rmFileFromExports(expFuncs, fname) {\n    delete expFuncs[fname];\n}\n\n/* Remove fname's entry in impFuncs */\nfunction rmFileFromImports(impFuncs, fname) {\n    delete impFuncs[fname];\n}\n\n/* Add a default export to expFuncs\n\nThree cases are handled here:\n1. CommonJS, assigning a function to module.exports (module.exports = function f() {};)\n3. AMD, when returning a function instead of an object with function being properties\n2. ES6 default export\nexpFuncs[fname]['default'] is a list, the following example illustrates why\n\nExample:\n    if (x) {\n        module.exports = function f() {};\n    } else {\n        module.exports = function g() {};\n    }\n\nArgs:\n    expFuncs - A dictionary storing export info with file names being keys\n       fname - A string, name of the enclosing file of the export statement\n          nd - An ast node, usually of type FunctionDeclaration\n*/\nfunction addDefaultExport(expFuncs, fname, nd) {\n    if (!(fname in expFuncs))\n        addFileToExports(expFuncs, fname);\n    expFuncs[fname]['default'].push(nd);\n}\n\n\n/*\nTo avoid the exported/imported function name colliding with Object Prototype's own properties,\nwe prepend '$' to exported/imported function name before inserting it into\nimpFuncs[fname][srcFname]['named'] and expFuncs[fname]['named'].\n\nExample:\n    If a developer exports a function called `hasOwnProperty`, it would override\n    the `hasOwnProperty` property of impFuncs[fname][srcFname]['named'] when we insert it, and break the code\n    Now we have a test for this case, please see tests/import-export/es6/es6-import-hasOwnProperty.js\n*/\nfunction mangle(funcName) {\n    return '$' + funcName;\n}\n\n/*\nSince connectEntireImport needs to use exportedName to construct PropVertex,\nwe need to unmangle exportedName first before using it.\n*/\nfunction unmangle(funcName) {\n    return funcName.substring(1, funcName.length);\n}\n\n/* Add a named export to expFuncs\n\nexpFuncs[fname]['named'][exportedName] is an ast node of type \"Identifier\"\nCase 1: export function funcName () { ... }\n    exportedName is simply funcName and\n    point expFuncs[fname]['named'][exportedName] to 'Identifer' node funcName\nCase 2: export { variable1 as name1, variable2 as name2, ...};\n    exportedName is name1\n    point expFuncs[fname]['named'][exportedName] to 'Identifer' node variable1\n\nArgs:\n        expFuncs - A dictionary storing export info with file names being keys\n           fname - A string, name of the enclosing file of the export statement\n           local - An ast node of type 'Identifer'\n    exportedName - A string, the name visible to outside\n*/\nfunction addNamedExport(expFuncs, fname, local, exportedName) {\n    if (!(fname in expFuncs))\n        addFileToExports(expFuncs, fname);\n\n    /* Re-assignment warning\n    Note that if (exportedName in expFuncs[fname]['named']) doesn't work here,\n    because exportedName can be properties of named's prototype,\n    for example, 'toString'.\n    */\n    exportedName = mangle(exportedName);\n    if (expFuncs[fname]['named'].hasOwnProperty(exportedName))\n        console.log('WARNING: Re-assignment in addNamedExport.');\n\n    expFuncs[fname]['named'][exportedName] = local;\n}\n\n/* Add a redirect export to expFuncs\n\nArgs:\n         expFuncs - A dictionary storing export info with file names being keys\n            fname - A string, name of the enclosing file of the export statement\n    redirectFnaem - A string, full path to the file being exported\n*/\nfunction addRedirectExport(expFuncs, fname, redirectFname) {\n    if (!(fname in expFuncs))\n        addFileToExports(expFuncs, fname);\n    expFuncs[fname]['redirect'].push(redirectFname);\n}\n\n/* Add a default import to impFuncs\n\nimpFuncs[fname][srcFname]['default'] is a list, please see the following example for why\n\nExample:\n    import a from \"module\";\n    import b from \"module\";\n\nArgs:\n    impFuncs - A dictionary storing import info with file names being keys\n       fname - A string, path of the enclosing file of the import statement\n    srcFname - A string, absolute path of the file being imported\n      idNode - An ast node of type 'Identifer'\n*/\nfunction addDefaultImport(impFuncs, fname, srcFname, idNode) {\n    if (!(fname in impFuncs))\n        impFuncs[fname] = {};\n\n    if (!(srcFname in impFuncs[fname]))\n        addSrcToFile(impFuncs, fname, srcFname);\n\n    impFuncs[fname][srcFname]['default'].push(idNode);\n}\n\n/* Add a named import to impFuncs\n\nimpFuncs[fname][srcFname]['named'][imported] is a list, please see the following example for why\n\nExample:\n    import { x as a } from \"module\";\n    import { x as b } from \"module\";\n\nArgs:\n        impFuncs - A dictionary storing import info with file names being keys\n           fname - A string, path of the enclosing file of the import statement\n        srcFname - A string, absolute path of the file being imported\n           local - An ast node of type \"Identifier\"\n    importedName - A string, the original name of imported value\n*/\nfunction addNamedImport(impFuncs, fname, srcFname, local, importedName) {\n    if (!(fname in impFuncs))\n        impFuncs[fname] = {};\n\n    if (!(srcFname in impFuncs[fname]))\n        addSrcToFile(impFuncs, fname, srcFname);\n\n    let named = impFuncs[fname][srcFname]['named'];\n\n    /*\n    Note that 'if (importedName in named)' doesn't work here,\n    because importedName can be properties of named's prototype,\n    for example, 'toString'.\n    */\n    importedName = mangle(importedName);\n    if (named.hasOwnProperty(importedName))\n        named[importedName].push(local);\n    else\n        named[importedName] = [local];\n}\n\n/* Add a entire import to impFuncs\n\nimpFuncs[fname][srcFname]['entire'] is a Boolean\nsince multiple entire imports are equivalent to any single one of them\n\nExample:\n    import * as a from \"module\";\n    import * as b from \"module\";\n\nArgs:\n    impFuncs - A dictionary storing import info with file names being keys\n       fname - A string, path of the enclosing file of the import statement\n    srcFname - A string, absolute path of the file being imported\n*/\nfunction addEntireImport(impFuncs, fname, srcFname) {\n    if (!(fname in impFuncs))\n        impFuncs[fname] = {};\n\n    if (!(srcFname in impFuncs[fname]))\n        addSrcToFile(impFuncs, fname, srcFname);\n\n    impFuncs[fname][srcFname]['entire'] = true;\n}\n\n/* Add edges from srcFname's default exports to nd in flow graph fg\n\nArgs:\n    expFuncs - A dictionary storing export info with file names being keys\n          fg - A graph, representing the flow graph\n    srcFname - A string, full path of the file being imported\n      idNode - An ast node of type 'Identifier', storing the alias of the default import\n\nTodo:\n    Do we need to handle cases other than nd being of type 'FunctionDeclaration'?\n*/\nfunction connectDefaultImport(expFuncs, fg, srcFname, idNode) {\n    if (!(srcFname in expFuncs))\n        return;\n    for (let expr of expFuncs[srcFname]['default']) {\n        if (expr.type === 'FunctionDeclaration') {\n            fg.addEdge(flowgraph.funcVertex(expr), flowgraph.vertexFor(idNode));\n        } else if (expr.type === 'ClassDeclaration' || expr.type === 'ClassExpression') {\n            let body = expr.body.body\n            for (var i = 0; i < body.length; ++i)\n              if (body[i].kind === 'constructor') {\n                  fg.addEdge(flowgraph.funcVertex(body[i].value), flowgraph.vertexFor(idNode));\n                }\n        } else {\n          fg.addEdge(flowgraph.vertexFor(expr), flowgraph.vertexFor(idNode));\n        }\n    }\n}\n\n/*\nArgs:\n        expFuncs - A dictionary storing export info with file names being keys\n              fg - A graph, representing the flow graph\n        srcFname - A string, full path of the file being imported\n    importedName - A string, the original name of the identifer being imported\n                 - can be used to search expFuncs[srcFame]['named']\n*/\nfunction connectNamedImport(expFuncs, fg, srcFname, local, importedName) {\n    if (!(srcFname in expFuncs))\n        return;\n\n    for (let redirectFname of expFuncs[srcFname]['redirect'])\n        connectNamedImport(expFuncs, fg, redirectFname, local, importedName);\n\n    let named = expFuncs[srcFname]['named'];\n\n    /*\n    Note that 'if (importedName in named)' doesn't work here,\n    because importedName can be properties of named's prototype,\n    for example, 'toString'.\n    */\n    if (!named.hasOwnProperty(importedName))\n        return;\n\n    fg.addEdge(flowgraph.vertexFor(named[importedName]), flowgraph.vertexFor(local));\n}\n\nfunction connectEntireImport(expFuncs, fg, srcFname) {\n    if (!(srcFname in expFuncs))\n        return;\n\n    for (let redirectFname of expFuncs[srcFname]['redirect'])\n        connectEntireImport(expFuncs, fg, redirectFname);\n\n    let named = expFuncs[srcFname]['named'];\n\n    for (let exportedName in named)\n        fg.addEdge(\n            flowgraph.vertexFor(named[exportedName]),\n            flowgraph.propVertex({ type: 'Literal', value: unmangle(exportedName) })\n        );\n}\n\n/* Return the relative import path to the project root directory\n\nArgs:\n       curPath - A string, path to the current file\n    importPath - A string, from source property of 'ImportDeclaration' node\n\nReturns:\n    A string, the relative import path to the project root directory\n*/\nfunction getRelativePath(curPath, importPath) {\n    let relativePath = path.join(curPath, '..', importPath);\n    return relativePath + '.js';\n}\n\n/* Iterate ast and collect export info into expFuncs\n\nArguments:\n         ast - a ProgramCollection\n    expFuncs - A dictionary storing export info with file names being keys\n    impFuncs - A dictionary storing import info with file names being keys\n\nRelevant docs:\n\n    interface CallExpression {\n        type: 'CallExpression';\n        callee: Expression;\n        arguments: ArgumentListElement[];\n    }\n\n    with\n\n    type ArgumentListElement = Expression | SpreadElement;\n*/\nfunction collectExportsImports(ast, expFuncs, impFuncs) {\n    for (let i = 0; i < ast.programs.length; i++) {\n        let fname = ast.programs[i].attr.filename;\n\n        astutil.visit(ast.programs[i], function (nd) {\n\n            /* -------------- exports -----------------*/\n\n            /* CommonJS\n            CommonJS is mostly automatically supported by the ACG algorithm due to its field-based nature\n            Here we handle the special case: module.exports = fn\n            Function astutil.isModuleExports check if nd is an assignment to module.exports\n            */\n            if (astutil.isModuleExports(nd)) {\n                addDefaultExport(expFuncs, fname, nd.right);\n            }\n\n            /* AMD\n            Handles: define(function() {return fn;})\n            */\n            if (astutil.isCallTo(nd, 'define')) {\n                // the last argument given to define is a function\n                const lastArg = nd.arguments[nd.arguments.length - 1];\n                if (!astutil.isFunction(lastArg))\n                    return;\n\n                const retVals = astutil.getReturnValues(lastArg);\n                for (let retVal of retVals)\n                    addDefaultExport(expFuncs, fname, retVal);\n            }\n\n            // ES6\n            if (nd.type === 'ExportDefaultDeclaration') {\n                addDefaultExport(expFuncs, fname, nd.declaration);\n            }\n\n            if (nd.type === 'ExportNamedDeclaration') {\n                if (nd.source) {\n                    const relativeImportPath = getRelativePath(fname, nd.source.value);\n                    addRedirectExport(expFuncs, fname, relativeImportPath);\n                }\n                else if (nd.declaration) {\n                    if (nd.declaration.type === 'FunctionDeclaration')\n                        addNamedExport(expFuncs, fname, nd.declaration.id, nd.declaration.id.name);\n                }\n                else\n                    for (let specifier of nd.specifiers)\n                        addNamedExport(expFuncs, fname, specifier.local, specifier.exported.name);\n            }\n\n            if (nd.type === 'ExportAllDeclaration') {\n                // TODO\n            }\n\n            /* -------------- imports -----------------*/\n\n            // require\n            if (nd.type === 'VariableDeclarator') {\n                let init = nd.init;\n\n                if (init && astutil.isCallTo(init, 'require')) {\n                    let requirePath = init.arguments[0].value;\n                    if (requirePath && typeof requirePath === 'string') {\n                        const relativeRequirePath = getRelativePath(fname, requirePath);\n                        addDefaultImport(impFuncs, fname, relativeRequirePath, nd.id);\n                    }\n                }\n            }\n\n            // import\n            if (nd.type === 'ImportDeclaration') {\n                const relativeImportPath = getRelativePath(fname, nd.source.value);\n\n                for (var i = 0; i < nd.specifiers.length; i++) {\n                    const specifier = nd.specifiers[i];\n                    switch (specifier.type) {\n                        case 'ImportSpecifier':\n                            addNamedImport(impFuncs, fname, relativeImportPath,\n                                           specifier.local, specifier.imported.name);\n                            break;\n                        case 'ImportDefaultSpecifier':\n                            addDefaultImport(impFuncs, fname, relativeImportPath, specifier.local);\n                            break;\n                        case 'ImportNamespaceSpecifier':\n                            addEntireImport(impFuncs, fname, relativeImportPath);\n                            break;\n                    }\n                }\n            }\n        });\n    }\n}\n\n/*\nArgs:\n          fg - A graph, representing the flow graph\n    expFuncs - A dictionary storing export info with file names being keys\n    impFuncs - A dictionary storing import info with file names being keys\n\nPostcondition:\n    edges connecting imports to the corresponding\n    exported value have been added to the flowgraph\n*/\nfunction connectImports(fg, expFuncs, impFuncs) {\n    // console.log(expFuncs);\n    // console.log(impFuncs);\n    for (let fname in impFuncs) {\n        for (let srcFname in impFuncs[fname]) {\n            if (!(srcFname in expFuncs))\n                continue;\n\n            let imp = impFuncs[fname][srcFname];\n\n            for (let idNode of imp['default'])\n                connectDefaultImport(expFuncs, fg, srcFname, idNode);\n\n            for (let importedName in imp['named'])\n                for (let local of imp['named'][importedName])\n                    connectNamedImport(expFuncs, fg, srcFname, local, importedName);\n\n            if (imp['entire'])\n                connectEntireImport(expFuncs, fg, srcFname);\n        }\n    }\n}\n\nmodule.exports.rmFileFromExports = rmFileFromExports;\nmodule.exports.rmFileFromImports = rmFileFromImports;\nmodule.exports.collectExportsImports = collectExportsImports;\nmodule.exports.connectImports = connectImports;\n"
  },
  {
    "path": "src/natives.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Module for adding standard library/DOM modelling to flow graph. */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var flowgraph = require('./flowgraph'),\n        nativeFlows = require('./harness').nativeFlows;\n\n    function addNativeFlowEdges(flow_graph) {\n        for (var native in nativeFlows) {\n            if (!nativeFlows.hasOwnProperty(native))\n                continue;\n            var target = nativeFlows[native];\n            flow_graph.addEdge(\n                flowgraph.nativeVertex(native),\n                flowgraph.propVertex({\n                    type: 'Identifier',\n                    name: target\n                })\n            );\n        }\n        return flow_graph;\n    }\n\n    exports.addNativeFlowEdges = addNativeFlowEdges;\n    return exports;\n});\n"
  },
  {
    "path": "src/numset.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/**\n * Facade module implementing sets of non-negative integers.\n * Allows to easily switch to a different implementation.\n */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    // var impl = require('./olist');\n    var impl = require('./set');\n\n    for (var p in impl)\n        exports[p] = impl[p];\n\n    return exports;\n});\n"
  },
  {
    "path": "src/olist.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/**\n * Implementation of sets of numbers as sorted lists. Singleton sets\n * are represented as single numbers, the empty set as undefined.\n */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    function size(a) {\n        if (typeof a === 'undefined')\n            return 0;\n\n        if (typeof a === 'number')\n            return 1;\n\n        return a.length;\n    }\n\n    /**\n     * Check whether set a contains number x.\n     */\n    function contains(a, x) {\n        if (typeof a === 'undefined')\n            return false;\n\n        if (typeof a === 'number')\n            return a === x;\n\n        var lo = 0, hi = a.length - 1, mid, elt;\n        while (lo <= hi) {\n            mid = (lo + hi) >> 1;\n            elt = a[mid];\n            if (elt === x) {\n                return true;\n            } else if (elt < x) {\n                lo = mid + 1;\n            } else {\n                hi = mid - 1;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Add number x to set a, and return the possibly modified a.\n     */\n    function add(a, x) {\n        if (typeof a === 'undefined')\n            return x;\n\n        if (typeof a === 'number') {\n            if (a < x)\n                return [a, x];\n            if (a > x)\n                return [x, a];\n            return a;\n        }\n\n        var lo = 0, hi = a.length - 1, mid, elt;\n        while (lo <= hi) {\n            mid = (lo + hi) >> 1;\n            elt = a[mid];\n            if (elt < x) {\n                lo = mid + 1;\n            } else if (elt > x) {\n                hi = mid - 1;\n            } else {\n                return a;\n            }\n        }\n        a.splice(lo, 0, x);\n        return a;\n    }\n\n    /**\n     * Add all elements in set b to set a, returning the resulting set.\n     * While set a may be modified, set b never is.\n     */\n    function addAll(a, b) {\n        if (typeof a === 'undefined')\n            return copy(b);\n        if (typeof b === 'undefined')\n            return a;\n\n        if (typeof a === 'number' && typeof b === 'object')\n            return add(b.slice(0), a);\n\n        // 'a' must be an array; check 'b'\n        var l1 = a.length;\n        if (l1 === 0)\n            return copy(b);\n\n        if (typeof b === 'number') {\n            return add(a, b);\n        } else {\n            var l2 = b.length;\n            if (l2 === 0)\n                return a;\n\n            var res = new Array(l1 + l2);\n            var i = 0, j = 0, k = 0;\n            while (i < l1 || j < l2) {\n                while (i < l1 && (j >= l2 || a[i] <= b[j]))\n                    res[k++] = a[i++];\n                while (k > 0 && j < l2 && b[j] === res[k - 1])\n                    ++j;\n                while (j < l2 && (i >= l1 || b[j] < a[i]))\n                    res[k++] = b[j++];\n            }\n            res.length = k;\n            return res;\n        }\n    }\n\n    /* Pitfall: this remove is inplace for array, not inplace for number */\n    function remove(a, x) {\n        if (typeof a === 'undefined')\n            return a;\n\n        if (typeof a === 'number')\n            return a === x ? void(0) : a;\n\n        var lo = 0, hi = a.length - 1, mid, elt;\n\n        if (lo === hi)\n            return a[0] === x ? void(0) : a;\n\n        while (lo <= hi) {\n            mid = (lo + hi) >> 1;\n            elt = a[mid];\n            if (elt < x) {\n                lo = mid + 1;\n            } else if (elt > x) {\n                hi = mid - 1;\n            } else {\n                a.splice(mid, 1);\n                return a;\n            }\n        }\n        return a;\n    }\n\n    function removeAll(a, b) {\n        if (typeof a === 'undefined' || typeof b === 'undefined')\n            return a;\n\n        if (typeof a === 'number')\n            return contains(b, a) ? void(0) : a;\n\n        if (typeof b === 'number')\n            return remove(a, b);\n\n        var i = 0, j = 0, k = 0, m = a.length, n = b.length;\n        while (i < m && j < n) {\n            while (i < m && a[i] < b[j])\n                a[k++] = a[i++];\n\n            if (i < m && a[i] === b[j])\n                ++i;\n\n            if (i < m)\n                while (j < n && a[i] > b[j])\n                    ++j;\n        }\n        while (i < m)\n            a[k++] = a[i++];\n\n        if (k) {\n            a.length = k;\n            return a;\n        } else {\n            return void(0);\n        }\n    }\n\n    function copy(a) {\n        if (typeof a === 'undefined' || typeof a === 'number')\n            return a;\n\n        return a.slice(0);\n    }\n\n    function iter(a, cb) {\n        if (a) {\n            if (typeof a === 'number')\n                cb(a);\n            else\n                a.forEach(cb);\n        }\n    }\n\n    function map(a, f) {\n        if (a) {\n            if (typeof a === 'number')\n                return [f(a)];\n            else\n                return a.map(f);\n        } else {\n            return [];\n        }\n    }\n\n    function some(a, f) {\n        var r = false;\n        if (a) {\n            if (typeof a === 'number')\n                return f(a);\n            else\n                for (var i = 0, l = a.length; i < l; ++i) {\n                    r = f(a);\n                    if (r)\n                        return r;\n                }\n        }\n        return r;\n    }\n\n    function all(a, f) {\n        var r = true;\n        if (a) {\n            if (typeof a === 'number')\n                return f(a);\n            else\n                for (var i = 0, l = a.length; i < l; ++i) {\n                    r = f(a);\n                    if (!r)\n                        return r;\n                }\n        }\n        return r;\n    }\n\n    function fromArray(ary) {\n        var a;\n        ary.forEach(function (x) {\n            a = add(a, x);\n        });\n        return a;\n    }\n\n    function toArray(a) {\n        return map(a, function f(x) {\n            return x;\n        });\n    }\n\n    exports.copy = copy;\n    exports.size = size;\n    exports.contains = contains;\n    exports.add = add;\n    exports.addAll = addAll;\n    exports.remove = remove;\n    exports.removeAll = removeAll;\n    exports.iter = iter;\n    exports.map = map;\n    exports.some = some;\n    exports.all = all;\n    exports.fromArray = fromArray;\n    exports.toArray = toArray;\n    return exports;\n});\n"
  },
  {
    "path": "src/pessimistic.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Pessimistic call graph builder. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var graph = require('./graph'),\n        natives = require('./natives'),\n        flowgraph = require('./flowgraph'),\n        callgraph = require('./callgraph');\n\n    function addOneShotEdges(ast, fg) {\n        // set up flow for one-shot calls\n        ast.attr.functions.forEach(function (fn) {\n            var parent = fn.attr.parent,\n                childProp = fn.attr.childProp;\n\n            if (childProp === 'callee' && parent &&\n                (parent.type === 'CallExpression' || parent.type === 'NewExpression')) {\n                // one-shot closure\n                parent.attr.oneshot = true;\n                for (var i = 0, nargs = parent.arguments.length; i < nargs; ++i) {\n                    if (i >= fn.params.length)\n                        break;\n                    fg.addEdge(flowgraph.argVertex(parent, i + 1), flowgraph.parmVertex(fn, i + 1));\n                }\n                fg.addEdge(flowgraph.retVertex(fn), flowgraph.resVertex(parent));\n            } else {\n                // not a one-shot closure\n                for (var i = 0, nparms = fn.params.length; i <= nparms; ++i)\n                    fg.addEdge(flowgraph.unknownVertex(), flowgraph.parmVertex(fn, i));\n                fg.addEdge(flowgraph.retVertex(fn), flowgraph.unknownVertex());\n            }\n        });\n\n        // set up flow for all other calls\n        ast.attr.calls.forEach(function (call) {\n            if (!call.attr.oneshot)\n                for (var i = 0, nargs = call.arguments.length; i <= nargs; ++i)\n                    fg.addEdge(flowgraph.argVertex(call, i), flowgraph.unknownVertex());\n            fg.addEdge(flowgraph.unknownVertex(), flowgraph.resVertex(call));\n        });\n    }\n\n    function buildCallGraph(ast, noOneShot) {\n        var fg = new graph.FlowGraph();\n        natives.addNativeFlowEdges(fg);\n        if (!noOneShot)\n            addOneShotEdges(ast, fg);\n        flowgraph.addIntraproceduralFlowGraphEdges(ast, fg);\n        return callgraph.extractCG(ast, fg);\n    }\n\n    exports.buildCallGraph = buildCallGraph;\n    return exports;\n});\n"
  },
  {
    "path": "src/requireJsGraph.js",
    "content": "if (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function(require, exports) {\n\n    var assert = require('assert'),\n        astutil = require('./astutil'),\n        _ = require('./underscore'),\n        fs = require('fs');\n\n\n    function makeRequireJsGraph(ast) {\n        assert.equal(1, ast.programs.length, \"Can only have one starting point at the moment.\");\n\n        var rx = /^.*\\\\(.+\\\\)*(.+)\\.(.+)$/g;\n        var regexParse = rx.exec(ast.programs[0].attr.filename);\n        var partialFileName = regexParse[2]  + \".js\",\n            fileName = \"./\" + partialFileName,\n            folder = regexParse[0].split(/[a-zA-Z]+\\.js/)[0].replace(/\\/$/, \"\\\\\");\n        var dependencyGraph = [];\n        astutil.visit(ast, function(node) {\n            switch (node.type) {\n                case 'CallExpression' :\n                    if (node.callee.name === \"define\" || node.callee.name === \"require\") {\n                        var dependencies = [], argument = node.arguments[0];\n                        if (argument.type === \"ArrayExpression\") {\n                            argument.elements.forEach(function(element) {\n                                dependencies.push(element.value + \".js\");\n                            });\n                        } else if (argument.type === \"Literal\") {\n                            dependencies.push(argument.value + \".js\");\n                        }\n                        dependencies.forEach(function(dependency) {\n                            dependencyGraph.push(new Dependency(fileName, dependency));\n                        });\n                    }\n                break;\n            }\n        });\n        dependencyGraph.map(function(dep){return dep.to}).forEach(function(outgoingDep) {\n            var normOutgoingDep = outgoingDep.replace(/^.\\//, \"\");\n            normOutgoingDep = normOutgoingDep.replace(/^\\//, \"\");\n            normOutgoingDep = normOutgoingDep.replace(/\\//, \"\\\\\");\n            var newStart = folder + normOutgoingDep;\n            if (fs.existsSync(newStart)) {\n                var referencedAST = astutil.astFromFiles([newStart]);\n                dependencyGraph = dependencyGraph.concat(makeRequireJsGraph(referencedAST))\n            }\n        });\n        return _.uniq(dependencyGraph, function(edge) {\n            return edge.toString();\n        });\n    }\n\n    function Dependency(from, to) {\n        this.from = from;\n        this.to = to;\n\n        this.toString = function() {\n            return removeLeadingPointSlash(this.from) + \" -> \" + removeLeadingPointSlash(this.to);\n        };\n\n        function removeLeadingPointSlash(path) {\n            return path.replace(/^\\.?\\//, \"\");\n        }\n    }\n    exports.makeRequireJsGraph = makeRequireJsGraph;\n    return exports;\n});"
  },
  {
    "path": "src/runner.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\ndefine(function (require, exports) {\n    const bindings = require('./bindings'),\n        astutil = require('./astutil'),\n        pessimistic = require('./pessimistic'),\n        semioptimistic = require('./semioptimistic'),\n        callbackCounter = require('./callbackCounter'),\n        requireJsGraph = require('./requireJsGraph'),\n        path = require('path'),\n        fs = require('fs'),\n        utils = require('./utils'),\n        JSONStream = require('JSONStream');\n    this.args = null;\n    this.files = null;\n    this.consoleOutput = null;\n\n    Array.prototype.remove = function () {\n        var what, a = arguments, L = a.length, ax;\n        while (L && this.length) {\n            what = a[--L];\n            while ((ax = this.indexOf(what)) !== -1) {\n                this.splice(ax, 1);\n            }\n        }\n        return this;\n    };\n\n    let addNode = function (edge, v) {\n        if (v.type === 'CalleeVertex') {\n            let nd = v.call;\n            edge.label = astutil.encFuncName(nd.attr.enclosingFunction);\n            edge.file = nd.attr.enclosingFile;\n            edge.start = {row: nd.loc.start.line, column: nd.loc.start.column};\n            edge.end = {row: nd.loc.end.line, column: nd.loc.end.column};\n            edge.range = {start: nd.range[0], end: nd.range[1]};\n            return edge;\n        }\n        if (v.type === 'FuncVertex') {\n            edge.label = astutil.funcname(v.func);\n            edge.file = v.func.attr.enclosingFile;\n            edge.start = {row: v.func.loc.start.line, column: v.func.loc.start.column};\n            edge.end = {row: v.func.loc.end.line, column: v.func.loc.end.column};\n            edge.range = {start: v.func.range[0], end: v.func.range[1]};\n            return edge;\n        }\n        if (v.type === 'NativeVertex') {\n            //'Math_log' (Native)\n            edge.label = v.name;\n            edge.file = \"Native\";\n            edge.start.row = null;\n            edge.end.row = null;\n            edge.start.column = null;\n            edge.end.column = null;\n            edge.range = {start: null, end: null};\n            return edge;\n        }\n        throw new Error(\"strange vertex: \" + v);\n    };\n\n    let buildBinding = function (call, fn) {\n        let edge = {\n            source: {\n                label: null,\n                file: null,\n                start: {row: null, column: null},\n                end: {row: null, column: null},\n                range: {start: null, end: null}\n            },\n            target: {\n                label: null,\n                file: null,\n                start: {row: null, column: null},\n                end: {row: null, column: null},\n                range: {start: null, end: null}\n            }\n        };\n        addNode(edge.source, call);\n        addNode(edge.target, fn);\n        return edge;\n    };\n\n    let pp = function (v) {\n        if (v.type === 'CalleeVertex')\n            return '\\'' + astutil.encFuncName(v.call.attr.enclosingFunction) + '\\' (' + astutil.ppPos(v.call) + ')';\n        if (v.type === 'FuncVertex')\n            return '\\'' + astutil.funcname(v.func) + '\\' (' + astutil.ppPos(v.func) + ')';\n        if (v.type === 'NativeVertex')\n            return '\\'' + v.name + '\\' (Native)';\n        throw new Error(\"strange vertex: \" + v);\n    };\n\n    let build = function () {\n        let args = this.args;\n        let files = this.files;\n        let consoleOutput = this.consoleOutput;\n\n        let filter = this.filter;\n\n        if (filter !== undefined && filter.length > 0) {\n            let filteredfiles = [];\n            files.forEach(function (file) {\n                filteredfiles.push(file);\n                filter.forEach(function (elem) {\n                    let trunk = elem.substr(1).trim();\n                    let expression = new RegExp(trunk, \"gm\");\n                    let result = expression.test(file);\n\n                    if (result && elem.startsWith('-')) {\n                        filteredfiles.remove(file);\n                    }\n\n                    if (result && elem.startsWith('+')) {\n                        filteredfiles.push(file);\n                    }\n\n                });\n            });\n            files = Array.from(new Set(filteredfiles));\n        }\n\n        args.strategy = args.strategy || 'ONESHOT';\n        if (!args.strategy.match(/^(NONE|ONESHOT|DEMAND|FULL)$/)) {\n            process.exit(-1);\n        }\n        if (args.strategy === 'FULL') {\n            console.warn('strategy FULL not implemented yet; using DEMAND instead');\n            args.strategy = 'DEMAND';\n        }\n        if (args.time) console.time(\"parsing  \");\n        var ast = astutil.astFromFiles(files);\n        if (args.time) console.timeEnd(\"parsing  \");\n\n        if (args.time) console.time(\"bindings \");\n        bindings.addBindings(ast);\n        if (args.time) console.timeEnd(\"bindings \");\n\n        if (args.time) console.time(\"callgraph\");\n        var cg;\n        if (args.strategy === 'NONE' || args.strategy === 'ONESHOT')\n            cg = pessimistic.buildCallGraph(ast, args.strategy === 'NONE');\n        else if (args.strategy === 'DEMAND')\n            cg = semioptimistic.buildCallGraph(ast);\n        if (args.time) console.timeEnd(\"callgraph\");\n\n        if (args.fg){\n            let serializedGraph = cg.fg.graph.serialize();\n            serializedGraph.links.forEach((link) => {\n                console.log(link.source, \"=>\", link.target);\n            });\n        }\n\n        if (args.countCB)\n            callbackCounter.countCallbacks(ast);\n\n        if (args.reqJs)\n            requireJsGraph.makeRequireJsGraph(ast).forEach(function (edge) {\n                console.log(edge.toString());\n            });\n        if (args.cg) {\n            let result = [];\n            cg.edges.iter(function (call, fn) {\n                result.push(buildBinding(call, fn));\n                if (consoleOutput)\n                    console.log(pp(call) + \" -> \" + pp(fn));\n            });\n            if (this.args.output !== null) {\n                let filename = this.args.output[0];\n                if (!filename.endsWith(\".json\")) {\n                    filename += \".json\";\n                }\n                fs.writeFile(filename, JSON.stringify(result, null, 2), function (err) {\n                    if (err) {\n                        /*\n                        When happened something wrong (usually out of memory when we want print\n                        the result into a file), then we try to file with JSONStream.\n                         */\n                        let transformStream = JSONStream.stringify();\n                        let outputStream = fs.createWriteStream(filename);\n                        transformStream.pipe(outputStream);\n                        result.forEach(transformStream.write);\n                        transformStream.end();\n                    }\n                });\n\n            }\n            return result;\n        }\n    };\n\n    exports.setFiles = function (inputList) {\n        let filelist = [];\n        inputList.forEach(function (file) {\n            file = path.resolve(file);\n            if (!fs.existsSync(file)) {\n                console.warn('The path \"' + file + '\" does not exists.');\n            }\n            else if (fs.statSync(file).isDirectory()) {\n                filelist = utils.collectFiles(file, filelist);\n            }\n            else if (file.endsWith(\".js\") || file.endsWith(\".ts\") || file.endsWith(\".vue\")) {\n                filelist.push(file);\n            }\n        });\n        this.files = Array.from(new Set(filelist));\n        if (this.files.length === 0) {\n            console.warn(\"Input file list is empty!\");\n            process.exit(-1);\n        }\n    };\n\n    exports.setFilter = function (filter) {\n        this.filter = filter;\n    };\n\n    exports.setArgs = function (args) {\n        this.args = args;\n    };\n\n    exports.setConsoleOutput = function (value) {\n        this.consoleOutput = value;\n    };\n\n    exports.build = build;\n    return exports;\n});"
  },
  {
    "path": "src/semioptimistic.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Optimistic call graph builder that tries to be clever about\n * which interprocedural flows to propagate: it only propagates\n * along edges that lead to a function call. */\n\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    var graph = require('./graph'),\n        natives = require('./natives'),\n        flowgraph = require('./flowgraph'),\n        callgraph = require('./callgraph'),\n        mod = require('./module'),\n        dftc = require('./dftc');\n\n    function addInterproceduralFlowEdges(ast, fg) {\n        fg = fg || new graph.FlowGraph();\n\n        var changed;\n        do {\n            changed = false;\n\n            var reach = dftc.reachability(fg, function (nd) {\n                return nd.type !== 'UnknownVertex';\n            });\n\n            ast.attr.calls.forEach(function (call) {\n                var res = flowgraph.resVertex(call);\n                if (!res.attr.interesting)\n                    reach.iterReachable(res, function (nd) {\n                        if (nd.type === 'CalleeVertex') {\n                            res.attr.interesting = true;\n                        }\n                    });\n            });\n\n            ast.attr.functions.forEach(function (fn) {\n                var interesting = false, nparams = fn.params.length;\n\n                for (var i = 0; i <= nparams; ++i) {\n                    var param = flowgraph.parmVertex(fn, i);\n                    if (!param.attr.interesting) {\n                        reach.iterReachable(param, function (nd) {\n                            if (nd.type === 'CalleeVertex') {\n                                param.attr.interesting = true;\n                            }\n                        });\n                    }\n                    interesting = interesting || param.attr.interesting;\n                }\n\n                reach.iterReachable(flowgraph.funcVertex(fn), function (nd) {\n                    if (nd.type === 'CalleeVertex') {\n                        var call = nd.call, res = flowgraph.resVertex(call);\n\n                        if (res.attr.interesting) {\n                            var ret = flowgraph.retVertex(fn);\n                            if (!fg.hasEdge(ret, res)) {\n                                changed = true;\n                                fg.addEdge(ret, res);\n                            }\n                        }\n\n                        if (interesting)\n                            for (var i = 0; i <= nparams; ++i) {\n                                if (i > call.arguments.length)\n                                    break;\n\n                                var param = flowgraph.parmVertex(fn, i);\n                                if (param.attr.interesting) {\n                                    var arg = flowgraph.argVertex(call, i);\n                                    if (!fg.hasEdge(arg, param)) {\n                                        changed = true;\n                                        fg.addEdge(arg, param);\n                                    }\n                                }\n                            }\n                    }\n                });\n            });\n        } while (changed); // until fixpoint\n\n        return fg;\n    }\n\n    function buildCallGraph(ast) {\n        var fg = new graph.FlowGraph();\n        natives.addNativeFlowEdges(fg);\n        flowgraph.addIntraproceduralFlowGraphEdges(ast, fg);\n\n        let expFuncs = {},\n            impFuncs = {};\n        mod.collectExportsImports(ast, expFuncs, impFuncs);\n        mod.connectImports(fg, expFuncs, impFuncs);\n\n        addInterproceduralFlowEdges(ast, fg);\n\n        return callgraph.extractCG(ast, fg);\n    }\n\n    exports.addInterproceduralFlowEdges = addInterproceduralFlowEdges;\n    exports.buildCallGraph = buildCallGraph;\n    return exports;\n});\n"
  },
  {
    "path": "src/set.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/*\n * Keep the interface of ./olist.js, but use ES6 Set under the hood\n */\n\nfunction size(s) {\n    if (typeof s === 'undefined')\n        return 0;\n\n    if (typeof s === 'number')\n        return 1;\n\n    return s.size;\n}\n\n/* Check whether set s contains number n */\nfunction contains(s, n) {\n    if (typeof s === 'undefined')\n        return false;\n\n    if (typeof s === 'number')\n        return s === n;\n\n    return s.has(n);\n}\n\n/* Add number n to set s, and return the possibly modified s */\nfunction add(s, n) {\n    if (typeof s === 'undefined')\n        return n;\n\n    if (typeof s === 'number')\n        return new Set([s, n]);\n\n    s.add(n);\n    return s;\n}\n\n/*\n * Add all elements in set s2 to set s1, return the resulting set\n * While set s1 may be modified, set s2 never is.\n */\nfunction addAll(s1, s2) {\n    if (typeof s1 === 'undefined')\n        return copy(s2);\n\n    if (typeof s2 === 'undefined')\n        return s1;\n\n    if (typeof s1 === 'number' && typeof s2 === 'number') {\n        return new Set([s1, s2]);\n    }\n    else if (typeof s1 === 'number' && typeof s2 === 'object') {\n        return new Set([s1, ...s2]);\n    }\n    else if (typeof s1 === 'object' && typeof s2 === 'number') {\n        s1.add(s2);\n        return s1;\n    }\n    else {\n        for (let n of s2)\n            s1.add(n);\n        return s1\n    }\n}\n\n/*\n * Remove number n from set s and return the modified set\n * Pitfall: this remove is inplace for array, not inplace for number\n */\nfunction remove(s, n) {\n    if (typeof s === 'undefined')\n        return s;\n\n    if (typeof s === 'number')\n        return s === n ? void(0) : s;\n\n    s.delete(n)\n    return s;\n}\n\n/*\n * Remove all elements in set s2 from set s1, return the resulting set\n */\nfunction removeAll(s1, s2) {\n    if (typeof s1 === 'undefined' || typeof s2 === 'undefined')\n        return s1;\n\n    if (typeof s1 === 'number')\n        return contains(s2, s1) ? void(0) : s1;\n\n    if (typeof s2 === 'number') {\n        s1.delete(s2);\n        return s1;\n    }\n\n    for (let n of s2)\n        s1.delete(n);\n\n    if (s1.size === 0)\n        return void(0);\n    else\n        return s1;\n}\n\nfunction copy(s) {\n    if (typeof s === 'undefined' || typeof s === 'number')\n        return s;\n\n    // Return a shallow clone of the original set s\n    return new Set(s);\n}\n\nfunction iter(s, cb) {\n    if (typeof s !== 'undefined') {\n        if (typeof s === 'number')\n            cb(s);\n        else\n            s.forEach(cb);\n    }\n}\n\nfunction map(s, f) {\n    if (typeof s !== 'undefined') {\n        if (typeof s === 'number')\n            return [f(s)];\n        else {\n            return Array.from(s).map(f);\n        }\n    }\n    else {\n        return [];\n    }\n}\n\nfunction fromArray(ary) {\n    return new Set(ary);\n}\n\nfunction toArray(s) {\n    if (typeof s === 'undefined')\n        return []\n\n    if (typeof s === 'number')\n        return [s]\n\n    return Array.from(s);\n}\n\nmodule.exports.size = size;\nmodule.exports.copy = copy;\nmodule.exports.contains = contains;\nmodule.exports.add = add;\nmodule.exports.addAll = addAll;\nmodule.exports.remove = remove;\nmodule.exports.removeAll = removeAll;\nmodule.exports.iter = iter;\nmodule.exports.map = map;\nmodule.exports.fromArray = fromArray;\nmodule.exports.toArray = toArray;\n\n"
  },
  {
    "path": "src/srcPreprocessor.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/*\n * This file includes the source preprocessors.\n * Preprocessors are meant to be run before the parser.\n * A preprocessor takes a string (src code) as input\n * and return a string (processed src code) as output.\n * All preprocessors should retain line numbers.\n */\n\nconst babel = require('@babel/core');\n\nconst nameToFunc = {\n\t'flow': stripFlowPrep,\n\t'hashbang': trimHashbangPrep\n};\n\n/* Apply a list of preprocessors to src\nArgs:\n\t      src - A string, the source code to be processed\n\t    fname - A string, name of the source file\n\tprepNames - A list of preprocessor names\n*/\nfunction applyPreps(src, fname, prepNames) {\n\ttry {\n\t\tfor (let prepName of prepNames)\n\t\t\tsrc = nameToFunc[prepName](src);\n\t}\n\tcatch (err) {\n        console.log('-------------------------------------------');\n        console.log('Warning: Preprocessing errored ' + fname);\n        console.log(err.stack);\n        console.log('-------------------------------------------');\n        return null;\n\t}\n\treturn src;\n}\n\nfunction stripFlowPrep(src) {\n    return babel.transform(src, {\n        presets: [\"@babel/preset-flow\"],\n        retainLines: true,\n        parserOpts: {strictMode: false}\n    }).code;\n}\n\n/* Trim hashbang to avoid the parser blowing up\nExample:\n    #!/usr/bin/env node\nReference:\n    https://github.com/jquery/esprima/issues/1151\n*/\nfunction trimHashbangPrep(src) {\n    if (src.substring(0, 2) === '#!') {\n        var end = src.indexOf('\\n');\n        var filler = '';\n        for (var i = 0; i < end; ++i) {\n           filler += ' ';\n        }\n        src = filler + src.substring(end, src.length);\n    }\n    return src;\n}\n\n/* Compile Typescript into plain Javascript\n\nGeneral reference: https://github.com/Microsoft/TypeScript-Babel-Starter\n\nPlugin @babel/typescript needs filename option to trigger,\nsee the following issue for details:\nhttps://github.com/babel/babel/issues/8065\n\nPlugins:\n\n    @babel/plugin-proposal-class-properties\n        https://medium.com/@jacobworrel/babels-transform-class-properties-plugin-how-it-works-and-what-it-means-for-your-react-apps-6983539ffc22\n        https://github.com/babel/babelify/issues/167\n*/\nfunction typescriptPrep(fname, src) {\n    return babel.transform(src, {\n        presets: [\"@babel/preset-typescript\"],\n        plugins: [\"@babel/plugin-proposal-class-properties\"],\n        filename: fname,\n        retainLines: true,\n        parserOpts: {strictMode: false}\n    }).code;\n}\n\nmodule.exports.applyPreps = applyPreps;\nmodule.exports.stripFlowPrep = stripFlowPrep;\nmodule.exports.trimHashbangPrep = trimHashbangPrep;\nmodule.exports.typescriptPrep = typescriptPrep;\n\n"
  },
  {
    "path": "src/symtab.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\n/* Simple implementation of symbol tables. Uses\n * prototypal inheritance to model scoping. */\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function (require, exports) {\n    function mangle(name) {\n        return '$' + name;\n    }\n\n    function isMangled(name) {\n        return name && name[0] === '$';\n    }\n\n    function Symtab(outer) {\n        var self = Object.create(outer || Symtab.prototype);\n        // every scope has a pointer to its outer scope, which may be null\n        self.outer = outer;\n        return self;\n    }\n\n    Symtab.prototype.get = function (name, deflt) {\n        var mangled = mangle(name);\n        if (!deflt || this.has(name))\n            return this[mangled];\n        this[mangled] = deflt;\n        return deflt;\n    };\n\n    Symtab.prototype.has = function (name) {\n        return mangle(name) in this;\n    };\n\n    Symtab.prototype.hasOwn = function (name) {\n        return this.hasOwnProperty(mangle(name));\n    };\n\n    Symtab.prototype.set = function (name, value) {\n        if (!name)\n            console.log('WARNING: name is falsy for Symtab, check bindings.js.');\n        return this[mangle(name)] = value;\n    };\n\n    Symtab.prototype.values = function () {\n        var values = [];\n        for (var p in this)\n            if (isMangled(p))\n                values[values.length] = this[p];\n        return values;\n    };\n\n    exports.Symtab = Symtab;\n    return exports;\n});\n"
  },
  {
    "path": "src/tests.js",
    "content": "// function go(x) { x = 3; }\nfunction y() {\nvar x = 1;\n}\n"
  },
  {
    "path": "src/underscore.js",
    "content": "//     Underscore.js 1.5.2\n//     http://underscorejs.org\n//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n//     Underscore may be freely distributed under the MIT license.\n\n(function() {\n\n    // Baseline setup\n    // --------------\n\n    // Establish the root object, `window` in the browser, or `exports` on the server.\n    var root = this;\n\n    // Save the previous value of the `_` variable.\n    var previousUnderscore = root._;\n\n    // Establish the object that gets returned to break out of a loop iteration.\n    var breaker = {};\n\n    // Save bytes in the minified (but not gzipped) version:\n    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n    // Create quick reference variables for speed access to core prototypes.\n    var\n        push             = ArrayProto.push,\n        slice            = ArrayProto.slice,\n        concat           = ArrayProto.concat,\n        toString         = ObjProto.toString,\n        hasOwnProperty   = ObjProto.hasOwnProperty;\n\n    // All **ECMAScript 5** native function implementations that we hope to use\n    // are declared here.\n    var\n        nativeForEach      = ArrayProto.forEach,\n        nativeMap          = ArrayProto.map,\n        nativeReduce       = ArrayProto.reduce,\n        nativeReduceRight  = ArrayProto.reduceRight,\n        nativeFilter       = ArrayProto.filter,\n        nativeEvery        = ArrayProto.every,\n        nativeSome         = ArrayProto.some,\n        nativeIndexOf      = ArrayProto.indexOf,\n        nativeLastIndexOf  = ArrayProto.lastIndexOf,\n        nativeIsArray      = Array.isArray,\n        nativeKeys         = Object.keys,\n        nativeBind         = FuncProto.bind;\n\n    // Create a safe reference to the Underscore object for use below.\n    var _ = function(obj) {\n        if (obj instanceof _) return obj;\n        if (!(this instanceof _)) return new _(obj);\n        this._wrapped = obj;\n    };\n\n    // Export the Underscore object for **Node.js**, with\n    // backwards-compatibility for the old `require()` API. If we're in\n    // the browser, add `_` as a global object via a string identifier,\n    // for Closure Compiler \"advanced\" mode.\n    if (typeof exports !== 'undefined') {\n        if (typeof module !== 'undefined' && module.exports) {\n            exports = module.exports = _;\n        }\n        exports._ = _;\n    } else {\n        root._ = _;\n    }\n\n    // Current version.\n    _.VERSION = '1.5.2';\n\n    // Collection Functions\n    // --------------------\n\n    // The cornerstone, an `each` implementation, aka `forEach`.\n    // Handles objects with the built-in `forEach`, arrays, and raw objects.\n    // Delegates to **ECMAScript 5**'s native `forEach` if available.\n    var each = _.each = _.forEach = function(obj, iterator, context) {\n        if (obj == null) return;\n        if (nativeForEach && obj.forEach === nativeForEach) {\n            obj.forEach(iterator, context);\n        } else if (obj.length === +obj.length) {\n            for (var i = 0, length = obj.length; i < length; i++) {\n                if (iterator.call(context, obj[i], i, obj) === breaker) return;\n            }\n        } else {\n            var keys = _.keys(obj);\n            for (var i = 0, length = keys.length; i < length; i++) {\n                if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;\n            }\n        }\n    };\n\n    // Return the results of applying the iterator to each element.\n    // Delegates to **ECMAScript 5**'s native `map` if available.\n    _.map = _.collect = function(obj, iterator, context) {\n        var results = [];\n        if (obj == null) return results;\n        if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n        each(obj, function(value, index, list) {\n            results.push(iterator.call(context, value, index, list));\n        });\n        return results;\n    };\n\n    var reduceError = 'Reduce of empty array with no initial value';\n\n    // **Reduce** builds up a single result from a list of values, aka `inject`,\n    // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n    _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n        var initial = arguments.length > 2;\n        if (obj == null) obj = [];\n        if (nativeReduce && obj.reduce === nativeReduce) {\n            if (context) iterator = _.bind(iterator, context);\n            return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n        }\n        each(obj, function(value, index, list) {\n            if (!initial) {\n                memo = value;\n                initial = true;\n            } else {\n                memo = iterator.call(context, memo, value, index, list);\n            }\n        });\n        if (!initial) throw new TypeError(reduceError);\n        return memo;\n    };\n\n    // The right-associative version of reduce, also known as `foldr`.\n    // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n    _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n        var initial = arguments.length > 2;\n        if (obj == null) obj = [];\n        if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n            if (context) iterator = _.bind(iterator, context);\n            return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n        }\n        var length = obj.length;\n        if (length !== +length) {\n            var keys = _.keys(obj);\n            length = keys.length;\n        }\n        each(obj, function(value, index, list) {\n            index = keys ? keys[--length] : --length;\n            if (!initial) {\n                memo = obj[index];\n                initial = true;\n            } else {\n                memo = iterator.call(context, memo, obj[index], index, list);\n            }\n        });\n        if (!initial) throw new TypeError(reduceError);\n        return memo;\n    };\n\n    // Return the first value which passes a truth test. Aliased as `detect`.\n    _.find = _.detect = function(obj, iterator, context) {\n        var result;\n        any(obj, function(value, index, list) {\n            if (iterator.call(context, value, index, list)) {\n                result = value;\n                return true;\n            }\n        });\n        return result;\n    };\n\n    // Return all the elements that pass a truth test.\n    // Delegates to **ECMAScript 5**'s native `filter` if available.\n    // Aliased as `select`.\n    _.filter = _.select = function(obj, iterator, context) {\n        var results = [];\n        if (obj == null) return results;\n        if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n        each(obj, function(value, index, list) {\n            if (iterator.call(context, value, index, list)) results.push(value);\n        });\n        return results;\n    };\n\n    // Return all the elements for which a truth test fails.\n    _.reject = function(obj, iterator, context) {\n        return _.filter(obj, function(value, index, list) {\n            return !iterator.call(context, value, index, list);\n        }, context);\n    };\n\n    // Determine whether all of the elements match a truth test.\n    // Delegates to **ECMAScript 5**'s native `every` if available.\n    // Aliased as `all`.\n    _.every = _.all = function(obj, iterator, context) {\n        iterator || (iterator = _.identity);\n        var result = true;\n        if (obj == null) return result;\n        if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n        each(obj, function(value, index, list) {\n            if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n        });\n        return !!result;\n    };\n\n    // Determine if at least one element in the object matches a truth test.\n    // Delegates to **ECMAScript 5**'s native `some` if available.\n    // Aliased as `any`.\n    var any = _.some = _.any = function(obj, iterator, context) {\n        iterator || (iterator = _.identity);\n        var result = false;\n        if (obj == null) return result;\n        if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n        each(obj, function(value, index, list) {\n            if (result || (result = iterator.call(context, value, index, list))) return breaker;\n        });\n        return !!result;\n    };\n\n    // Determine if the array or object contains a given value (using `===`).\n    // Aliased as `include`.\n    _.contains = _.include = function(obj, target) {\n        if (obj == null) return false;\n        if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n        return any(obj, function(value) {\n            return value === target;\n        });\n    };\n\n    // Invoke a method (with arguments) on every item in a collection.\n    _.invoke = function(obj, method) {\n        var args = slice.call(arguments, 2);\n        var isFunc = _.isFunction(method);\n        return _.map(obj, function(value) {\n            return (isFunc ? method : value[method]).apply(value, args);\n        });\n    };\n\n    // Convenience version of a common use case of `map`: fetching a property.\n    _.pluck = function(obj, key) {\n        return _.map(obj, function(value){ return value[key]; });\n    };\n\n    // Convenience version of a common use case of `filter`: selecting only objects\n    // containing specific `key:value` pairs.\n    _.where = function(obj, attrs, first) {\n        if (_.isEmpty(attrs)) return first ? void 0 : [];\n        return _[first ? 'find' : 'filter'](obj, function(value) {\n            for (var key in attrs) {\n                if (attrs[key] !== value[key]) return false;\n            }\n            return true;\n        });\n    };\n\n    // Convenience version of a common use case of `find`: getting the first object\n    // containing specific `key:value` pairs.\n    _.findWhere = function(obj, attrs) {\n        return _.where(obj, attrs, true);\n    };\n\n    // Return the maximum element or (element-based computation).\n    // Can't optimize arrays of integers longer than 65,535 elements.\n    // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)\n    _.max = function(obj, iterator, context) {\n        if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n            return Math.max.apply(Math, obj);\n        }\n        if (!iterator && _.isEmpty(obj)) return -Infinity;\n        var result = {computed : -Infinity, value: -Infinity};\n        each(obj, function(value, index, list) {\n            var computed = iterator ? iterator.call(context, value, index, list) : value;\n            computed > result.computed && (result = {value : value, computed : computed});\n        });\n        return result.value;\n    };\n\n    // Return the minimum element (or element-based computation).\n    _.min = function(obj, iterator, context) {\n        if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n            return Math.min.apply(Math, obj);\n        }\n        if (!iterator && _.isEmpty(obj)) return Infinity;\n        var result = {computed : Infinity, value: Infinity};\n        each(obj, function(value, index, list) {\n            var computed = iterator ? iterator.call(context, value, index, list) : value;\n            computed < result.computed && (result = {value : value, computed : computed});\n        });\n        return result.value;\n    };\n\n    // Shuffle an array, using the modern version of the\n    // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisherâ€“Yates_shuffle).\n    _.shuffle = function(obj) {\n        var rand;\n        var index = 0;\n        var shuffled = [];\n        each(obj, function(value) {\n            rand = _.random(index++);\n            shuffled[index - 1] = shuffled[rand];\n            shuffled[rand] = value;\n        });\n        return shuffled;\n    };\n\n    // Sample **n** random values from an array.\n    // If **n** is not specified, returns a single random element from the array.\n    // The internal `guard` argument allows it to work with `map`.\n    _.sample = function(obj, n, guard) {\n        if (arguments.length < 2 || guard) {\n            return obj[_.random(obj.length - 1)];\n        }\n        return _.shuffle(obj).slice(0, Math.max(0, n));\n    };\n\n    // An internal function to generate lookup iterators.\n    var lookupIterator = function(value) {\n        return _.isFunction(value) ? value : function(obj){ return obj[value]; };\n    };\n\n    // Sort the object's values by a criterion produced by an iterator.\n    _.sortBy = function(obj, value, context) {\n        var iterator = lookupIterator(value);\n        return _.pluck(_.map(obj, function(value, index, list) {\n            return {\n                value: value,\n                index: index,\n                criteria: iterator.call(context, value, index, list)\n            };\n        }).sort(function(left, right) {\n                var a = left.criteria;\n                var b = right.criteria;\n                if (a !== b) {\n                    if (a > b || a === void 0) return 1;\n                    if (a < b || b === void 0) return -1;\n                }\n                return left.index - right.index;\n            }), 'value');\n    };\n\n    // An internal function used for aggregate \"group by\" operations.\n    var group = function(behavior) {\n        return function(obj, value, context) {\n            var result = {};\n            var iterator = value == null ? _.identity : lookupIterator(value);\n            each(obj, function(value, index) {\n                var key = iterator.call(context, value, index, obj);\n                behavior(result, key, value);\n            });\n            return result;\n        };\n    };\n\n    // Groups the object's values by a criterion. Pass either a string attribute\n    // to group by, or a function that returns the criterion.\n    _.groupBy = group(function(result, key, value) {\n        (_.has(result, key) ? result[key] : (result[key] = [])).push(value);\n    });\n\n    // Indexes the object's values by a criterion, similar to `groupBy`, but for\n    // when you know that your index values will be unique.\n    _.indexBy = group(function(result, key, value) {\n        result[key] = value;\n    });\n\n    // Counts instances of an object that group by a certain criterion. Pass\n    // either a string attribute to count by, or a function that returns the\n    // criterion.\n    _.countBy = group(function(result, key) {\n        _.has(result, key) ? result[key]++ : result[key] = 1;\n    });\n\n    // Use a comparator function to figure out the smallest index at which\n    // an object should be inserted so as to maintain order. Uses binary search.\n    _.sortedIndex = function(array, obj, iterator, context) {\n        iterator = iterator == null ? _.identity : lookupIterator(iterator);\n        var value = iterator.call(context, obj);\n        var low = 0, high = array.length;\n        while (low < high) {\n            var mid = (low + high) >>> 1;\n            iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n        }\n        return low;\n    };\n\n    // Safely create a real, live array from anything iterable.\n    _.toArray = function(obj) {\n        if (!obj) return [];\n        if (_.isArray(obj)) return slice.call(obj);\n        if (obj.length === +obj.length) return _.map(obj, _.identity);\n        return _.values(obj);\n    };\n\n    // Return the number of elements in an object.\n    _.size = function(obj) {\n        if (obj == null) return 0;\n        return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n    };\n\n    // Array Functions\n    // ---------------\n\n    // Get the first element of an array. Passing **n** will return the first N\n    // values in the array. Aliased as `head` and `take`. The **guard** check\n    // allows it to work with `_.map`.\n    _.first = _.head = _.take = function(array, n, guard) {\n        if (array == null) return void 0;\n        return (n == null) || guard ? array[0] : slice.call(array, 0, n);\n    };\n\n    // Returns everything but the last entry of the array. Especially useful on\n    // the arguments object. Passing **n** will return all the values in\n    // the array, excluding the last N. The **guard** check allows it to work with\n    // `_.map`.\n    _.initial = function(array, n, guard) {\n        return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n    };\n\n    // Get the last element of an array. Passing **n** will return the last N\n    // values in the array. The **guard** check allows it to work with `_.map`.\n    _.last = function(array, n, guard) {\n        if (array == null) return void 0;\n        if ((n == null) || guard) {\n            return array[array.length - 1];\n        } else {\n            return slice.call(array, Math.max(array.length - n, 0));\n        }\n    };\n\n    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n    // Especially useful on the arguments object. Passing an **n** will return\n    // the rest N values in the array. The **guard**\n    // check allows it to work with `_.map`.\n    _.rest = _.tail = _.drop = function(array, n, guard) {\n        return slice.call(array, (n == null) || guard ? 1 : n);\n    };\n\n    // Trim out all falsy values from an array.\n    _.compact = function(array) {\n        return _.filter(array, _.identity);\n    };\n\n    // Internal implementation of a recursive `flatten` function.\n    var flatten = function(input, shallow, output) {\n        if (shallow && _.every(input, _.isArray)) {\n            return concat.apply(output, input);\n        }\n        each(input, function(value) {\n            if (_.isArray(value) || _.isArguments(value)) {\n                shallow ? push.apply(output, value) : flatten(value, shallow, output);\n            } else {\n                output.push(value);\n            }\n        });\n        return output;\n    };\n\n    // Flatten out an array, either recursively (by default), or just one level.\n    _.flatten = function(array, shallow) {\n        return flatten(array, shallow, []);\n    };\n\n    // Return a version of the array that does not contain the specified value(s).\n    _.without = function(array) {\n        return _.difference(array, slice.call(arguments, 1));\n    };\n\n    // Produce a duplicate-free version of the array. If the array has already\n    // been sorted, you have the option of using a faster algorithm.\n    // Aliased as `unique`.\n    _.uniq = _.unique = function(array, isSorted, iterator, context) {\n        if (_.isFunction(isSorted)) {\n            context = iterator;\n            iterator = isSorted;\n            isSorted = false;\n        }\n        var initial = iterator ? _.map(array, iterator, context) : array;\n        var results = [];\n        var seen = [];\n        each(initial, function(value, index) {\n            if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n                seen.push(value);\n                results.push(array[index]);\n            }\n        });\n        return results;\n    };\n\n    // Produce an array that contains the union: each distinct element from all of\n    // the passed-in arrays.\n    _.union = function() {\n        return _.uniq(_.flatten(arguments, true));\n    };\n\n    // Produce an array that contains every item shared between all the\n    // passed-in arrays.\n    _.intersection = function(array) {\n        var rest = slice.call(arguments, 1);\n        return _.filter(_.uniq(array), function(item) {\n            return _.every(rest, function(other) {\n                return _.indexOf(other, item) >= 0;\n            });\n        });\n    };\n\n    // Take the difference between one array and a number of other arrays.\n    // Only the elements present in just the first array will remain.\n    _.difference = function(array) {\n        var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n        return _.filter(array, function(value){ return !_.contains(rest, value); });\n    };\n\n    // Zip together multiple lists into a single array -- elements that share\n    // an index go together.\n    _.zip = function() {\n        var length = _.max(_.pluck(arguments, \"length\").concat(0));\n        var results = new Array(length);\n        for (var i = 0; i < length; i++) {\n            results[i] = _.pluck(arguments, '' + i);\n        }\n        return results;\n    };\n\n    // Converts lists into objects. Pass either a single array of `[key, value]`\n    // pairs, or two parallel arrays of the same length -- one of keys, and one of\n    // the corresponding values.\n    _.object = function(list, values) {\n        if (list == null) return {};\n        var result = {};\n        for (var i = 0, length = list.length; i < length; i++) {\n            if (values) {\n                result[list[i]] = values[i];\n            } else {\n                result[list[i][0]] = list[i][1];\n            }\n        }\n        return result;\n    };\n\n    // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n    // we need this function. Return the position of the first occurrence of an\n    // item in an array, or -1 if the item is not included in the array.\n    // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n    // If the array is large and already in sort order, pass `true`\n    // for **isSorted** to use binary search.\n    _.indexOf = function(array, item, isSorted) {\n        if (array == null) return -1;\n        var i = 0, length = array.length;\n        if (isSorted) {\n            if (typeof isSorted == 'number') {\n                i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);\n            } else {\n                i = _.sortedIndex(array, item);\n                return array[i] === item ? i : -1;\n            }\n        }\n        if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n        for (; i < length; i++) if (array[i] === item) return i;\n        return -1;\n    };\n\n    // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n    _.lastIndexOf = function(array, item, from) {\n        if (array == null) return -1;\n        var hasIndex = from != null;\n        if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n            return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n        }\n        var i = (hasIndex ? from : array.length);\n        while (i--) if (array[i] === item) return i;\n        return -1;\n    };\n\n    // Generate an integer Array containing an arithmetic progression. A port of\n    // the native Python `range()` function. See\n    // [the Python documentation](http://docs.python.org/library/functions.html#range).\n    _.range = function(start, stop, step) {\n        if (arguments.length <= 1) {\n            stop = start || 0;\n            start = 0;\n        }\n        step = arguments[2] || 1;\n\n        var length = Math.max(Math.ceil((stop - start) / step), 0);\n        var idx = 0;\n        var range = new Array(length);\n\n        while(idx < length) {\n            range[idx++] = start;\n            start += step;\n        }\n\n        return range;\n    };\n\n    // Function (ahem) Functions\n    // ------------------\n\n    // Reusable constructor function for prototype setting.\n    var ctor = function(){};\n\n    // Create a function bound to a given object (assigning `this`, and arguments,\n    // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n    // available.\n    _.bind = function(func, context) {\n        var args, bound;\n        if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n        if (!_.isFunction(func)) throw new TypeError;\n        args = slice.call(arguments, 2);\n        return bound = function() {\n            if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));\n            ctor.prototype = func.prototype;\n            var self = new ctor;\n            ctor.prototype = null;\n            var result = func.apply(self, args.concat(slice.call(arguments)));\n            if (Object(result) === result) return result;\n            return self;\n        };\n    };\n\n    // Partially apply a function by creating a version that has had some of its\n    // arguments pre-filled, without changing its dynamic `this` context.\n    _.partial = function(func) {\n        var args = slice.call(arguments, 1);\n        return function() {\n            return func.apply(this, args.concat(slice.call(arguments)));\n        };\n    };\n\n    // Bind all of an object's methods to that object. Useful for ensuring that\n    // all callbacks defined on an object belong to it.\n    _.bindAll = function(obj) {\n        var funcs = slice.call(arguments, 1);\n        if (funcs.length === 0) throw new Error(\"bindAll must be passed function names\");\n        each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n        return obj;\n    };\n\n    // Memoize an expensive function by storing its results.\n    _.memoize = function(func, hasher) {\n        var memo = {};\n        hasher || (hasher = _.identity);\n        return function() {\n            var key = hasher.apply(this, arguments);\n            return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n        };\n    };\n\n    // Delays a function for the given number of milliseconds, and then calls\n    // it with the arguments supplied.\n    _.delay = function(func, wait) {\n        var args = slice.call(arguments, 2);\n        return setTimeout(function(){ return func.apply(null, args); }, wait);\n    };\n\n    // Defers a function, scheduling it to run after the current call stack has\n    // cleared.\n    _.defer = function(func) {\n        return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n    };\n\n    // Returns a function, that, when invoked, will only be triggered at most once\n    // during a given window of time. Normally, the throttled function will run\n    // as much as it can, without ever going more than once per `wait` duration;\n    // but if you'd like to disable the execution on the leading edge, pass\n    // `{leading: false}`. To disable execution on the trailing edge, ditto.\n    _.throttle = function(func, wait, options) {\n        var context, args, result;\n        var timeout = null;\n        var previous = 0;\n        options || (options = {});\n        var later = function() {\n            previous = options.leading === false ? 0 : new Date;\n            timeout = null;\n            result = func.apply(context, args);\n        };\n        return function() {\n            var now = new Date;\n            if (!previous && options.leading === false) previous = now;\n            var remaining = wait - (now - previous);\n            context = this;\n            args = arguments;\n            if (remaining <= 0) {\n                clearTimeout(timeout);\n                timeout = null;\n                previous = now;\n                result = func.apply(context, args);\n            } else if (!timeout && options.trailing !== false) {\n                timeout = setTimeout(later, remaining);\n            }\n            return result;\n        };\n    };\n\n    // Returns a function, that, as long as it continues to be invoked, will not\n    // be triggered. The function will be called after it stops being called for\n    // N milliseconds. If `immediate` is passed, trigger the function on the\n    // leading edge, instead of the trailing.\n    _.debounce = function(func, wait, immediate) {\n        var timeout, args, context, timestamp, result;\n        return function() {\n            context = this;\n            args = arguments;\n            timestamp = new Date();\n            var later = function() {\n                var last = (new Date()) - timestamp;\n                if (last < wait) {\n                    timeout = setTimeout(later, wait - last);\n                } else {\n                    timeout = null;\n                    if (!immediate) result = func.apply(context, args);\n                }\n            };\n            var callNow = immediate && !timeout;\n            if (!timeout) {\n                timeout = setTimeout(later, wait);\n            }\n            if (callNow) result = func.apply(context, args);\n            return result;\n        };\n    };\n\n    // Returns a function that will be executed at most one time, no matter how\n    // often you call it. Useful for lazy initialization.\n    _.once = function(func) {\n        var ran = false, memo;\n        return function() {\n            if (ran) return memo;\n            ran = true;\n            memo = func.apply(this, arguments);\n            func = null;\n            return memo;\n        };\n    };\n\n    // Returns the first function passed as an argument to the second,\n    // allowing you to adjust arguments, run code before and after, and\n    // conditionally execute the original function.\n    _.wrap = function(func, wrapper) {\n        return function() {\n            var args = [func];\n            push.apply(args, arguments);\n            return wrapper.apply(this, args);\n        };\n    };\n\n    // Returns a function that is the composition of a list of functions, each\n    // consuming the return value of the function that follows.\n    _.compose = function() {\n        var funcs = arguments;\n        return function() {\n            var args = arguments;\n            for (var i = funcs.length - 1; i >= 0; i--) {\n                args = [funcs[i].apply(this, args)];\n            }\n            return args[0];\n        };\n    };\n\n    // Returns a function that will only be executed after being called N times.\n    _.after = function(times, func) {\n        return function() {\n            if (--times < 1) {\n                return func.apply(this, arguments);\n            }\n        };\n    };\n\n    // Object Functions\n    // ----------------\n\n    // Retrieve the names of an object's properties.\n    // Delegates to **ECMAScript 5**'s native `Object.keys`\n    _.keys = nativeKeys || function(obj) {\n        if (obj !== Object(obj)) throw new TypeError('Invalid object');\n        var keys = [];\n        for (var key in obj) if (_.has(obj, key)) keys.push(key);\n        return keys;\n    };\n\n    // Retrieve the values of an object's properties.\n    _.values = function(obj) {\n        var keys = _.keys(obj);\n        var length = keys.length;\n        var values = new Array(length);\n        for (var i = 0; i < length; i++) {\n            values[i] = obj[keys[i]];\n        }\n        return values;\n    };\n\n    // Convert an object into a list of `[key, value]` pairs.\n    _.pairs = function(obj) {\n        var keys = _.keys(obj);\n        var length = keys.length;\n        var pairs = new Array(length);\n        for (var i = 0; i < length; i++) {\n            pairs[i] = [keys[i], obj[keys[i]]];\n        }\n        return pairs;\n    };\n\n    // Invert the keys and values of an object. The values must be serializable.\n    _.invert = function(obj) {\n        var result = {};\n        var keys = _.keys(obj);\n        for (var i = 0, length = keys.length; i < length; i++) {\n            result[obj[keys[i]]] = keys[i];\n        }\n        return result;\n    };\n\n    // Return a sorted list of the function names available on the object.\n    // Aliased as `methods`\n    _.functions = _.methods = function(obj) {\n        var names = [];\n        for (var key in obj) {\n            if (_.isFunction(obj[key])) names.push(key);\n        }\n        return names.sort();\n    };\n\n    // Extend a given object with all the properties in passed-in object(s).\n    _.extend = function(obj) {\n        each(slice.call(arguments, 1), function(source) {\n            if (source) {\n                for (var prop in source) {\n                    obj[prop] = source[prop];\n                }\n            }\n        });\n        return obj;\n    };\n\n    // Return a copy of the object only containing the whitelisted properties.\n    _.pick = function(obj) {\n        var copy = {};\n        var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n        each(keys, function(key) {\n            if (key in obj) copy[key] = obj[key];\n        });\n        return copy;\n    };\n\n    // Return a copy of the object without the blacklisted properties.\n    _.omit = function(obj) {\n        var copy = {};\n        var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n        for (var key in obj) {\n            if (!_.contains(keys, key)) copy[key] = obj[key];\n        }\n        return copy;\n    };\n\n    // Fill in a given object with default properties.\n    _.defaults = function(obj) {\n        each(slice.call(arguments, 1), function(source) {\n            if (source) {\n                for (var prop in source) {\n                    if (obj[prop] === void 0) obj[prop] = source[prop];\n                }\n            }\n        });\n        return obj;\n    };\n\n    // Create a (shallow-cloned) duplicate of an object.\n    _.clone = function(obj) {\n        if (!_.isObject(obj)) return obj;\n        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n    };\n\n    // Invokes interceptor with the obj, and then returns obj.\n    // The primary purpose of this method is to \"tap into\" a method chain, in\n    // order to perform operations on intermediate results within the chain.\n    _.tap = function(obj, interceptor) {\n        interceptor(obj);\n        return obj;\n    };\n\n    // Internal recursive comparison function for `isEqual`.\n    var eq = function(a, b, aStack, bStack) {\n        // Identical objects are equal. `0 === -0`, but they aren't identical.\n        // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).\n        if (a === b) return a !== 0 || 1 / a == 1 / b;\n        // A strict comparison is necessary because `null == undefined`.\n        if (a == null || b == null) return a === b;\n        // Unwrap any wrapped objects.\n        if (a instanceof _) a = a._wrapped;\n        if (b instanceof _) b = b._wrapped;\n        // Compare `[[Class]]` names.\n        var className = toString.call(a);\n        if (className != toString.call(b)) return false;\n        switch (className) {\n            // Strings, numbers, dates, and booleans are compared by value.\n            case '[object String]':\n                // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n                // equivalent to `new String(\"5\")`.\n                return a == String(b);\n            case '[object Number]':\n                // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n                // other numeric values.\n                return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n            case '[object Date]':\n            case '[object Boolean]':\n                // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n                // millisecond representations. Note that invalid dates with millisecond representations\n                // of `NaN` are not equivalent.\n                return +a == +b;\n            // RegExps are compared by their source patterns and flags.\n            case '[object RegExp]':\n                return a.source == b.source &&\n                    a.global == b.global &&\n                    a.multiline == b.multiline &&\n                    a.ignoreCase == b.ignoreCase;\n        }\n        if (typeof a != 'object' || typeof b != 'object') return false;\n        // Assume equality for cyclic structures. The algorithm for detecting cyclic\n        // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n        var length = aStack.length;\n        while (length--) {\n            // Linear search. Performance is inversely proportional to the number of\n            // unique nested structures.\n            if (aStack[length] == a) return bStack[length] == b;\n        }\n        // Objects with different constructors are not equivalent, but `Object`s\n        // from different frames are.\n        var aCtor = a.constructor, bCtor = b.constructor;\n        if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n            _.isFunction(bCtor) && (bCtor instanceof bCtor))) {\n            return false;\n        }\n        // Add the first object to the stack of traversed objects.\n        aStack.push(a);\n        bStack.push(b);\n        var size = 0, result = true;\n        // Recursively compare objects and arrays.\n        if (className == '[object Array]') {\n            // Compare array lengths to determine if a deep comparison is necessary.\n            size = a.length;\n            result = size == b.length;\n            if (result) {\n                // Deep compare the contents, ignoring non-numeric properties.\n                while (size--) {\n                    if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n                }\n            }\n        } else {\n            // Deep compare objects.\n            for (var key in a) {\n                if (_.has(a, key)) {\n                    // Count the expected number of properties.\n                    size++;\n                    // Deep compare each member.\n                    if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n                }\n            }\n            // Ensure that both objects contain the same number of properties.\n            if (result) {\n                for (key in b) {\n                    if (_.has(b, key) && !(size--)) break;\n                }\n                result = !size;\n            }\n        }\n        // Remove the first object from the stack of traversed objects.\n        aStack.pop();\n        bStack.pop();\n        return result;\n    };\n\n    // Perform a deep comparison to check if two objects are equal.\n    _.isEqual = function(a, b) {\n        return eq(a, b, [], []);\n    };\n\n    // Is a given array, string, or object empty?\n    // An \"empty\" object has no enumerable own-properties.\n    _.isEmpty = function(obj) {\n        if (obj == null) return true;\n        if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n        for (var key in obj) if (_.has(obj, key)) return false;\n        return true;\n    };\n\n    // Is a given value a DOM element?\n    _.isElement = function(obj) {\n        return !!(obj && obj.nodeType === 1);\n    };\n\n    // Is a given value an array?\n    // Delegates to ECMA5's native Array.isArray\n    _.isArray = nativeIsArray || function(obj) {\n        return toString.call(obj) == '[object Array]';\n    };\n\n    // Is a given variable an object?\n    _.isObject = function(obj) {\n        return obj === Object(obj);\n    };\n\n    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n    each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n        _['is' + name] = function(obj) {\n            return toString.call(obj) == '[object ' + name + ']';\n        };\n    });\n\n    // Define a fallback version of the method in browsers (ahem, IE), where\n    // there isn't any inspectable \"Arguments\" type.\n    if (!_.isArguments(arguments)) {\n        _.isArguments = function(obj) {\n            return !!(obj && _.has(obj, 'callee'));\n        };\n    }\n\n    // Optimize `isFunction` if appropriate.\n    if (typeof (/./) !== 'function') {\n        _.isFunction = function(obj) {\n            return typeof obj === 'function';\n        };\n    }\n\n    // Is a given object a finite number?\n    _.isFinite = function(obj) {\n        return isFinite(obj) && !isNaN(parseFloat(obj));\n    };\n\n    // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n    _.isNaN = function(obj) {\n        return _.isNumber(obj) && obj != +obj;\n    };\n\n    // Is a given value a boolean?\n    _.isBoolean = function(obj) {\n        return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n    };\n\n    // Is a given value equal to null?\n    _.isNull = function(obj) {\n        return obj === null;\n    };\n\n    // Is a given variable undefined?\n    _.isUndefined = function(obj) {\n        return obj === void 0;\n    };\n\n    // Shortcut function for checking if an object has a given property directly\n    // on itself (in other words, not on a prototype).\n    _.has = function(obj, key) {\n        return hasOwnProperty.call(obj, key);\n    };\n\n    // Utility Functions\n    // -----------------\n\n    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n    // previous owner. Returns a reference to the Underscore object.\n    _.noConflict = function() {\n        root._ = previousUnderscore;\n        return this;\n    };\n\n    // Keep the identity function around for default iterators.\n    _.identity = function(value) {\n        return value;\n    };\n\n    // Run a function **n** times.\n    _.times = function(n, iterator, context) {\n        var accum = Array(Math.max(0, n));\n        for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n        return accum;\n    };\n\n    // Return a random integer between min and max (inclusive).\n    _.random = function(min, max) {\n        if (max == null) {\n            max = min;\n            min = 0;\n        }\n        return min + Math.floor(Math.random() * (max - min + 1));\n    };\n\n    // List of HTML entities for escaping.\n    var entityMap = {\n        escape: {\n            '&': '&amp;',\n            '<': '&lt;',\n            '>': '&gt;',\n            '\"': '&quot;',\n            \"'\": '&#x27;'\n        }\n    };\n    entityMap.unescape = _.invert(entityMap.escape);\n\n    // Regexes containing the keys and values listed immediately above.\n    var entityRegexes = {\n        escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n        unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n    };\n\n    // Functions for escaping and unescaping strings to/from HTML interpolation.\n    _.each(['escape', 'unescape'], function(method) {\n        _[method] = function(string) {\n            if (string == null) return '';\n            return ('' + string).replace(entityRegexes[method], function(match) {\n                return entityMap[method][match];\n            });\n        };\n    });\n\n    // If the value of the named `property` is a function then invoke it with the\n    // `object` as context; otherwise, return it.\n    _.result = function(object, property) {\n        if (object == null) return void 0;\n        var value = object[property];\n        return _.isFunction(value) ? value.call(object) : value;\n    };\n\n    // Add your own custom functions to the Underscore object.\n    _.mixin = function(obj) {\n        each(_.functions(obj), function(name) {\n            var func = _[name] = obj[name];\n            _.prototype[name] = function() {\n                var args = [this._wrapped];\n                push.apply(args, arguments);\n                return result.call(this, func.apply(_, args));\n            };\n        });\n    };\n\n    // Generate a unique integer id (unique within the entire client session).\n    // Useful for temporary DOM ids.\n    var idCounter = 0;\n    _.uniqueId = function(prefix) {\n        var id = ++idCounter + '';\n        return prefix ? prefix + id : id;\n    };\n\n    // By default, Underscore uses ERB-style template delimiters, change the\n    // following template settings to use alternative delimiters.\n    _.templateSettings = {\n        evaluate    : /<%([\\s\\S]+?)%>/g,\n        interpolate : /<%=([\\s\\S]+?)%>/g,\n        escape      : /<%-([\\s\\S]+?)%>/g\n    };\n\n    // When customizing `templateSettings`, if you don't want to define an\n    // interpolation, evaluation or escaping regex, we need one that is\n    // guaranteed not to match.\n    var noMatch = /(.)^/;\n\n    // Certain characters need to be escaped so that they can be put into a\n    // string literal.\n    var escapes = {\n        \"'\":      \"'\",\n        '\\\\':     '\\\\',\n        '\\r':     'r',\n        '\\n':     'n',\n        '\\t':     't',\n        '\\u2028': 'u2028',\n        '\\u2029': 'u2029'\n    };\n\n    var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n    // JavaScript micro-templating, similar to John Resig's implementation.\n    // Underscore templating handles arbitrary delimiters, preserves whitespace,\n    // and correctly escapes quotes within interpolated code.\n    _.template = function(text, data, settings) {\n        var render;\n        settings = _.defaults({}, settings, _.templateSettings);\n\n        // Combine delimiters into one regular expression via alternation.\n        var matcher = new RegExp([\n            (settings.escape || noMatch).source,\n            (settings.interpolate || noMatch).source,\n            (settings.evaluate || noMatch).source\n        ].join('|') + '|$', 'g');\n\n        // Compile the template source, escaping string literals appropriately.\n        var index = 0;\n        var source = \"__p+='\";\n        text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n            source += text.slice(index, offset)\n                .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n            if (escape) {\n                source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n            }\n            if (interpolate) {\n                source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n            }\n            if (evaluate) {\n                source += \"';\\n\" + evaluate + \"\\n__p+='\";\n            }\n            index = offset + match.length;\n            return match;\n        });\n        source += \"';\\n\";\n\n        // If a variable is not specified, place data values in local scope.\n        if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n        source = \"var __t,__p='',__j=Array.prototype.join,\" +\n            \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n            source + \"return __p;\\n\";\n\n        try {\n            render = new Function(settings.variable || 'obj', '_', source);\n        } catch (e) {\n            e.source = source;\n            throw e;\n        }\n\n        if (data) return render(data, _);\n        var template = function(data) {\n            return render.call(this, data, _);\n        };\n\n        // Provide the compiled function source as a convenience for precompilation.\n        template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n        return template;\n    };\n\n    // Add a \"chain\" function, which will delegate to the wrapper.\n    _.chain = function(obj) {\n        return _(obj).chain();\n    };\n\n    // OOP\n    // ---------------\n    // If Underscore is called as a function, it returns a wrapped object that\n    // can be used OO-style. This wrapper holds altered versions of all the\n    // underscore functions. Wrapped objects may be chained.\n\n    // Helper function to continue chaining intermediate results.\n    var result = function(obj) {\n        return this._chain ? _(obj).chain() : obj;\n    };\n\n    // Add all of the Underscore functions to the wrapper object.\n    _.mixin(_);\n\n    // Add all mutator Array functions to the wrapper.\n    each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n        var method = ArrayProto[name];\n        _.prototype[name] = function() {\n            var obj = this._wrapped;\n            method.apply(obj, arguments);\n            if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n            return result.call(this, obj);\n        };\n    });\n\n    // Add all accessor Array functions to the wrapper.\n    each(['concat', 'join', 'slice'], function(name) {\n        var method = ArrayProto[name];\n        _.prototype[name] = function() {\n            return result.call(this, method.apply(this._wrapped, arguments));\n        };\n    });\n\n    _.extend(_.prototype, {\n\n        // Start chaining a wrapped Underscore object.\n        chain: function() {\n            this._chain = true;\n            return this;\n        },\n\n        // Extracts the result from a wrapped and chained object.\n        value: function() {\n            return this._wrapped;\n        }\n\n    });\n\n}).call(this);\n"
  },
  {
    "path": "src/utils.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\n/**\n * Collect all the files in the given directory, recursively\n */\nfunction collectFiles(dir, filelist) {\n    let files = fs.readdirSync(dir);\n    filelist = filelist || [];\n    files.forEach(function (file) {\n        if (fs.statSync(path.join(dir, file)).isDirectory()) {\n            filelist = collectFiles(path.join(dir, file), filelist);\n        }\n        else if (file.endsWith(\".js\")) {\n            filelist.push(path.join(dir, file));\n        }\n    });\n    return filelist;\n}\n\nmodule.exports.collectFiles = collectFiles;\n"
  },
  {
    "path": "tests/README.md",
    "content": "# Test Documentation\n\n## Overview\n\nOur tests consist of two parts: unit tests run by jest and integration tests run by a test framework written in python. The jest component is relatively straightforward, so we'll focus more on the python test framework.\n\nEach test case in the python framework again has two parts: the Javascript source code and the ground truth file containing the correct call graph. The python framework runs our tool against the js source code and compares the output with the ground truth file.\n\n* `test/test.py`: the entry point, loops over all the test directories and finds all js files. They it tries to find a .truth file that has the same name with the js file. These two files together form a test case. It calls `precision_recall` function and determine the correctness of a test case.\n* `test/process.py`: implements the `precision_recall` function. Given the tool's output and the truth file, computes the precision and recall.\n* `test/callgraph.py`: runs our tool and captures the call graph output through subprocess.\n* `test/required_files.py`: given a js file, find the other js files that it requires.\n\n## How to add a new test case\n\nSimply add all the js files and a truth file under one of the test directories specified in `test/test.py`. The python framework will automatically collect the new test case. Note that the truth file needs to have the same name with one of the js files, only within which function calls are checked.\n\n## Details\n\n* `test/process.py` and `test/callgraph.py` ignore edges that have at least one native end point.\n* If a test case is composed of multiple js files, only the function calls in the one that has same name with the truth file are checked.\n"
  },
  {
    "path": "tests/basics/arrow.js",
    "content": "arrowFunc = x => { return x; };\n\narrowFunc(10);\n"
  },
  {
    "path": "tests/basics/arrow.truth",
    "content": "arrow.js:global:3 -> arrow.js:anon:1\n"
  },
  {
    "path": "tests/basics/assignment.js",
    "content": "// This file tests assigning a function object to an existing local variable\nfunction main() {\n\tlet a = 1;\n\tlet b = function funcB () {\n\t\tconsole.log('funcB is called!');\n\t};\n\ta = b;\n\ta();\n}\n\nmain();\n"
  },
  {
    "path": "tests/basics/assignment.truth",
    "content": "assignment.js:funcB:5 -> Native\nassignment.js:main:8 -> assignment.js:funcB:4\nassignment.js:global:11 -> assignment.js:main:2\n"
  },
  {
    "path": "tests/basics/global-as-prop.js",
    "content": "/*\nSince we introduced `GlobVertex`, this problem has been fixed and we can now distinguish\nbetween the two function calls in this file.\n\nOriginal Comment:\n    This file illustrates one of the unexpected behaviors of the call graph algorithm\n    The algorithm should be able to distinguish the following two function calls,\n    however, variables in global scope are handled by creating property vertex in the flow graph\n*/\n\nlet a = function (x) { return x; };\nlet b = { 'a': function (x) { return x; }};\n\nb.a()\na()\n"
  },
  {
    "path": "tests/basics/global-as-prop.truth",
    "content": "global-as-prop.js:global:14 -> global-as-prop.js:a:12\nglobal-as-prop.js:global:15 -> global-as-prop.js:anon:11\n"
  },
  {
    "path": "tests/basics/local-is-fine.js",
    "content": "// Same code with global-as-prop.js, wrapped in a function\n(function () {\n  let a = function (x) { return x; };\n  let b = {'a': function (x) { return x; }};\n  a();\n  b.a();\n}());\n"
  },
  {
    "path": "tests/basics/local-is-fine.truth",
    "content": "local-is-fine.js:global:2 -> local-is-fine.js:anon:2\nlocal-is-fine.js:anon:5 -> local-is-fine.js:anon:3\nlocal-is-fine.js:anon:6 -> local-is-fine.js:a:4\n"
  },
  {
    "path": "tests/basics/method-def.js",
    "content": "var obj = {\n    randomMethod1: function () {\n        return 42;\n    },\n    'randomMethod2': function () {\n        return 'red';\n    }\n}\n\nobj.randomMethod1();\nobj.randomMethod2();\n"
  },
  {
    "path": "tests/basics/method-def.truth",
    "content": "method-def.js:global:10 -> method-def.js:randomMethod1:2\nmethod-def.js:global:11 -> method-def.js:randomMethod2:5\n"
  },
  {
    "path": "tests/callgraph.py",
    "content": "# Summary: Methods for collecting callgraph output\n#          and formatting it into truth file output\n\nimport subprocess\nimport re\n\nNODE_PROGRAM = 'js-callgraph'\n\n\ndef callgraph(files):\n    \"\"\"Returns raw standard output from callgraph generator\"\"\"\n    program = ['node', NODE_PROGRAM, '--cg', *files, '--strategy', 'DEMAND']\n\n    process = subprocess.run(program, stdout=subprocess.PIPE,\n                             stderr=subprocess.PIPE)\n\n    return process.stdout\n\n\ndef callgraph_formatted(files, keep='', natives=True):\n    \"\"\"Returns reformatted standard output from callgraph generator\n\n    Arguments:\n        files - list of files to run callgraph on\n         keep - set to a filename if only that file's calls are desired\n      natives - set to False to filter out native calls\n    \"\"\"\n    stdout = callgraph(files)\n    lines = str(stdout)[2:-1].split('\\\\n')[:-1]\n\n    frmttd_lines = []\n    for line in lines:\n        # ignore exceptions caused by formatting js output other than call edges (for example, warnings)\n        try:\n            frmttd_line = format_output(line)\n        except:\n            continue\n        frmttd_lines.append(frmttd_line)\n\n    if keep:\n        reg = re.compile(keep + r':.*:[0-9]+ ->.*')\n        frmttd_lines = [line for line in frmttd_lines if reg.match(line)]\n\n    if not natives:\n        frmttd_lines = [line for line in frmttd_lines if 'Native' not in line]\n\n    return frmttd_lines\n\n\n# Regex representing call graph\ncall_func = r'\\'(.*)\\' \\(([^@]*)@([0-9]*):[0-9]*-[0-9]*\\)'\nnative = r'\\'(.*)\\' \\(Native\\)'\n\nreg_func = re.compile(call_func + ' -> ' + call_func)\nreg_native = re.compile(call_func + ' -> ' + native)\n\n\ndef format_func(out):\n    \"\"\"Convert function call to truth file format.\n\n    >>> format_func(\"'global' (arrow.js@3:33-46) -> 'anon' (arrow.js@1:12-30)\")\n    'arrow.js:global:3 -> arrow.js:anon:1'\n    \"\"\"\n    m = reg_func.match(out)\n\n    fn_name1 = m.group(1)\n    file1 = m.group(2)\n    line1 = m.group(3)\n\n    fn_name2 = m.group(4)\n    file2 = m.group(5)\n    line2 = m.group(6)\n\n    output = '{0}:{1}:{2} -> {3}:{4}:{5}'\n\n    return output.format(file1, fn_name1, line1, file2, fn_name2, line2)\n\n\ndef format_native(out):\n    \"\"\"Convert native call to truth file format\n\n    >>> format_native(\"'global' (a.js@1:1-3) -> 'eval' (Native)\")\n    'a.js:global:1 -> Native'\n    \"\"\"\n    m = reg_native.match(out)\n\n    fn_name1 = m.group(1)\n    file1 = m.group(2)\n    line1 = m.group(3)\n\n    native_name = m.group(4)\n\n    output = '{0}:{1}:{2} -> Native'\n\n    return output.format(file1, fn_name1, line1)\n\n\ndef format_output(out):\n    \"\"\"Convert either a function call or a native call to truth file format\n\n    >>> format_ouput(\"'global' (arrow.js@3:3-16) -> 'anon' (arrow.js@1:12-30)\")\n    'arrow.js:global:3 -> arrow.js:anon:1'\n    >>> format_output(\"'global' (a.js@1:1-3) -> 'eval' (Native)\")\n    'a.js:global:1 -> Native'\n    \"\"\"\n    if reg_native.match(out):\n        return format_native(out)\n    else:\n        return format_func(out)\n"
  },
  {
    "path": "tests/classes/anonymous-class.js",
    "content": "export default class {\n  constructor () {\n    this.p = 0;\n  }\n}\n"
  },
  {
    "path": "tests/classes/basic-class.js",
    "content": "function Apple () {\n  this.grow = function () {\n\n  }\n}\n\napple = new Apple();\napple.grow();\n"
  },
  {
    "path": "tests/classes/basic-class.truth",
    "content": "basic-class.js:global:7 -> basic-class.js:Apple:1\nbasic-class.js:global:8 -> basic-class.js:anon:2\n"
  },
  {
    "path": "tests/classes/basic-class2.js",
    "content": "class Apple {\n  grow () {\n\n  }\n}\n\napple = new Apple();\napple.grow();\n"
  },
  {
    "path": "tests/classes/basic-class2.truth",
    "content": "basic-class2.js:global:8 -> basic-class2.js:grow:2\n"
  },
  {
    "path": "tests/classes/class-expression1.js",
    "content": "let x = class Apple {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nx();\n"
  },
  {
    "path": "tests/classes/class-expression1.truth",
    "content": "class-expression1.js:global:7 -> class-expression1.js:constructor:2\n"
  },
  {
    "path": "tests/classes/class-expression2.js",
    "content": "let x = class {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nx();\n"
  },
  {
    "path": "tests/classes/class-expression2.truth",
    "content": "class-expression2.js:global:7 -> class-expression2.js:constructor:2\n"
  },
  {
    "path": "tests/classes/class.js",
    "content": "class Rectangle {\n  constructor(height, width) {\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n  get area() {\n    return this.calcArea();\n  }\n  // Method\n  calcArea() {\n    return this.height * this.width;\n  }\n}\n\nconst square = new Rectangle(10, 10);\n\nconsole.log(square.calcArea());\n"
  },
  {
    "path": "tests/classes/class.truth",
    "content": "class.js:area:8 -> class.js:calcArea:11\nclass.js:global:16 -> class.js:constructor:2\nclass.js:global:18 -> Native\nclass.js:global:18 -> class.js:calcArea:11\n"
  },
  {
    "path": "tests/classes/export-class-expression1.js",
    "content": "let x = class Apple {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nexport default x;\n"
  },
  {
    "path": "tests/classes/export-class-expression2.js",
    "content": "let x = class {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nexport default x;\n"
  },
  {
    "path": "tests/classes/import-anonymous-class.js",
    "content": "import a from 'anonymous-class';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-anonymous-class.truth",
    "content": "import-anonymous-class.js:global:3 -> anonymous-class.js:constructor:2\n"
  },
  {
    "path": "tests/classes/import-class-expression1.js",
    "content": "import a from 'export-class-expression1';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-class-expression1.truth",
    "content": "import-class-expression1.js:global:3 -> export-class-expression1.js:constructor:2\n"
  },
  {
    "path": "tests/classes/import-class-expression2.js",
    "content": "import a from 'export-class-expression2';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-class-expression2.truth",
    "content": "import-class-expression2.js:global:3 -> export-class-expression2.js:constructor:2\n"
  },
  {
    "path": "tests/classes/outer-fn.js",
    "content": "function f2() {\n    return 5\n}\n\nclass A {\n    f() {\n        f2()\n    }\n}\n"
  },
  {
    "path": "tests/classes/outer-fn.truth",
    "content": "outer-fn.js:f:7 -> outer-fn.js:f2:1\n"
  },
  {
    "path": "tests/creating-vue-compiled.txt",
    "content": "The steps to making the vue-compiled directory were:\n\n1. copy the entire vue directory to a fold called vue-compiled\n2. Run this script in the directory above it\n\n\tfor f in $(find ./vue-compiled -name '*.js'); \n\tdo \n\t  $(babel --presets flow $f > $f.o)\n\t  echo $f\n\n\tdone\n\nThis traverses the directories and runs babel on each of the files and saves their compiled output to a .js.o file with the same name and location.\n"
  },
  {
    "path": "tests/es6/array-pattern.js",
    "content": "/*\nArray destructuing: basic variable assignment\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tconst a = [ () => { return 1; } ];\n\tlet [b] = a;\n\tb();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/array-pattern.truth",
    "content": "array-pattern.js:main:8 -> array-pattern.js:anon:6\narray-pattern.js:global:11 -> array-pattern.js:main:5\n"
  },
  {
    "path": "tests/es6/array-pattern2.js",
    "content": "/*\nArray destructuing: assignment separate from declaration\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tlet b;\n\tconst a = [ () => { return 1; } ];\n\t[b] = a;\n\tb();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/array-pattern2.truth",
    "content": "array-pattern2.js:main:9 -> array-pattern2.js:anon:7\narray-pattern2.js:global:12 -> array-pattern2.js:main:5\n"
  },
  {
    "path": "tests/es6/array-pattern3.js",
    "content": "/*\nArray destructuing: parsing an array returned from a function\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tconst f = () => { return [() => { return 1; }]; };\n\tconst [a] = f();\n\ta();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/array-pattern3.truth",
    "content": "array-pattern3.js:main:7 -> array-pattern3.js:anon:6\narray-pattern3.js:main:8 -> array-pattern3.js:anon:6\narray-pattern3.js:global:11 -> array-pattern3.js:main:5\n"
  },
  {
    "path": "tests/es6/array-pattern4.js",
    "content": "/*\nArray destructuing: ignoring some return values\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tconst f = () => { return [2, 3, () => { return 1; }]; };\n\tconst [,,a] = f();\n\ta();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/array-pattern4.truth",
    "content": "array-pattern4.js:main:7 -> array-pattern4.js:anon:6\narray-pattern4.js:main:8 -> array-pattern4.js:anon:6\narray-pattern4.js:global:11 -> array-pattern4.js:main:5\n"
  },
  {
    "path": "tests/es6/binding-pattern-global.js",
    "content": "let v = () => { return 1; };\n\nfunction main () {\n\tv();\n\t[v] = [null];\n}\n\nmain();\n/*\nThis test illustrates how the current implementation incorrectly set decl_scope\nfor 'BindingPattern' in binding.js.\nThe arrow functinon defined on line 1 is called on line 4.\nBut when the 'ArrayPattern' on line 5 is visited, the name 'v' is added to local symbol table.\nLater when flowgraph.js adds intra-procedural edges for line 4, the new edge will be\n\n\tVar(v) -> Callee(4)\n\ninstead of\n\n\tProp(v) -> Callee(4)\n\nresulting the call to arrow function defined on line 1 not detected.\n*/\n"
  },
  {
    "path": "tests/es6/binding-pattern-global.truth",
    "content": "binding-pattern-global.js:main:4 -> binding-pattern-global.js:anon:1\nbinding-pattern-global.js:global:8 -> binding-pattern-global.js:main:3\n"
  },
  {
    "path": "tests/es6/destructured-parameter.js",
    "content": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters\n*/\nfunction main () {\n\tfunction f ([x, y], {z}) {\n\t\treturn x() + y + z();\n\t}\n\tconst f2 = () => { return 2; };\n\tconst f3 = () => { return 3; };\n\tf([f2, 2], {z: f3});\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/destructured-parameter.truth",
    "content": "destructured-parameter.js:f:8 -> destructured-parameter.js:anon:10\ndestructured-parameter.js:f:8 -> destructured-parameter.js:anon:11\ndestructured-parameter.js:main:12 -> destructured-parameter.js:f:7\ndestructured-parameter.js:global:15 -> destructured-parameter.js:main:6\n"
  },
  {
    "path": "tests/es6/destructured-parameter2.js",
    "content": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters\n*/\nlet v = function () { return 0; };\n\nfunction main () {\n\tfunction f ({u: {v}}) {\n\t\treturn v();\n\t}\n\tconst f2 = () => { return 2; };\n\tf({u: {v: f2}});\n}\n\nmain();\n\n/*\nBefore supporting nested destructuring, running\n\n\tnode src/main.js --cg tests/es6/destructured-parameter2.js --strategy DEMAND\n\ngives the following output:\n\n\t'f' (destructured-parameter2.js@10:262-265) -> 'anon' (destructured-parameter2.js@6:181-206)\n\t'f' (destructured-parameter2.js@10:262-265) -> 'anon' (destructured-parameter2.js@12:282-301)\n\t'main' (destructured-parameter2.js@13:304-319) -> 'f' (destructured-parameter2.js@9:229-269)\n\t'global' (destructured-parameter2.js@16:324-330) -> 'main' (destructured-parameter2.js@8:209-322)\n\nNote that the anonymous function defined on line 6 and assigned to\nglobal variable v is never called in the program, which our algorithm mistakenly detects that\nit's called by function f.\nThis is due to the nested destructuring on line 9 is not handled correctly.\nv on line 9 is not found in the scope, and thus is considered as a global variable at line 10,\nwhich leads to the error of connecting Prop(v) -> Callee(10).\n*/"
  },
  {
    "path": "tests/es6/destructured-parameter2.truth",
    "content": "destructured-parameter2.js:f:10 -> destructured-parameter2.js:anon:12\ndestructured-parameter2.js:main:13 -> destructured-parameter2.js:f:9\ndestructured-parameter2.js:global:16 -> destructured-parameter2.js:main:8\n"
  },
  {
    "path": "tests/es6/destructured-parameter3.js",
    "content": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters\n*/\nlet v = function () { return 0; };\n\nfunction main () {\n\tfunction f ([u, [v]]) {\n\t\treturn u + v();\n\t}\n\tconst f2 = () => { return 2; };\n\tf([1, [f2]]);\n}\n\nmain();\n\n/*\nBefore supporting nested destructuring, running\n\n\tnode src/main.js --cg tests/es6/destructured-parameter3.js --strategy DEMAND\n\ngives the following output:\n\n\t'f' (destructured-parameter3.js@10:266-269) -> 'undefined' (destructured-parameter3.js@6:181-206)\n\t'f' (destructured-parameter3.js@10:266-269) -> 'undefined' (destructured-parameter3.js@12:286-305)\n\t'main' (destructured-parameter3.js@13:308-320) -> 'f' (destructured-parameter3.js@9:229-273)\n\t'global' (destructured-parameter3.js@16:325-331) -> 'main' (destructured-parameter3.js@8:209-323)\n\nNote that the anonymous function defined on line 6 and assigned to\nglobal variable v is never called in the program, which our algorithm mistakenly detects that\nit's called by function f.\nThis is due to the nested destructuring on line 9 is not handled correctly.\nv on line 9 is not found in the scope, and thus is considered as a global variable at line 10,\nwhich leads to the error of connecting Prop(v) -> Callee(10).\n*/"
  },
  {
    "path": "tests/es6/destructured-parameter3.truth",
    "content": "destructured-parameter3.js:f:10 -> destructured-parameter3.js:anon:12\ndestructured-parameter3.js:main:13 -> destructured-parameter3.js:f:9\ndestructured-parameter3.js:global:16 -> destructured-parameter3.js:main:8\n"
  },
  {
    "path": "tests/es6/lib.js",
    "content": "export const sqrt = Math.sqrt;\nexport function square(x) {\n    return x * x;\n}\nexport function diag(x, y) {\n    return sqrt(square(x) + square(y));\n}\n"
  },
  {
    "path": "tests/es6/main.js",
    "content": "import { square, diag } from 'lib';\nconsole.log(square(11)); // 121\nconsole.log(diag(4, 3)); // 5\n"
  },
  {
    "path": "tests/es6/main.truth",
    "content": "main.js:global:2 -> Native\nmain.js:global:2 -> lib.js:square:2\nmain.js:global:3 -> Native\nmain.js:global:3 -> lib.js:diag:5\n"
  },
  {
    "path": "tests/es6/object-pattern.js",
    "content": "/*\nObject destructuing: basic assignment\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tconst b = {'a': () => { return 1; } };\n\tconst {a} = b;\n\ta();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/object-pattern.truth",
    "content": "object-pattern.js:main:8 -> object-pattern.js:anon:6\nobject-pattern.js:global:11 -> object-pattern.js:main:5\n"
  },
  {
    "path": "tests/es6/object-pattern2.js",
    "content": "/*\nObject destructuing: assign without declaration\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tlet a;\n\tconst b = {'a': () => { return 1; } };\n\t({a} = b);\n\ta();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/object-pattern2.truth",
    "content": "object-pattern2.js:main:9 -> object-pattern2.js:anon:7\nobject-pattern2.js:global:12 -> object-pattern2.js:main:5\n"
  },
  {
    "path": "tests/es6/object-pattern3.js",
    "content": "/*\nObject destructuing: assigning to new variable names\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n*/\nfunction main () {\n\tconst b = {'a': () => { return 1; } };\n\tconst {a: foo} = b;\n\tfoo();\n}\n\nmain();\n"
  },
  {
    "path": "tests/es6/object-pattern3.truth",
    "content": "object-pattern3.js:main:8 -> object-pattern3.js:anon:6\nobject-pattern3.js:global:11 -> object-pattern3.js:main:5\n"
  },
  {
    "path": "tests/ground_truths/create-component.txt",
    "content": "create-component.js.o:anon:3 -> Native\ncreate-component.js.o:anon:9 -> Native\ncreate-component.js.o:anon:11 -> create-component.js.o:_interopRequireDefault:27\ncreate-component.js.o:anon:13 -> Native\ncreate-component.js.o:anon:15 -> Native\ncreate-component.js.o:anon:17 -> Native\ncreate-component.js.o:anon:19 -> Native\ncreate-component.js.o:anon:21 -> Native\ncreate-component.js.o:anon:23 -> Native\ncreate-component.js.o:anon:25 -> Native\ncreate-component.js.o:anon:29 -> create-component.js.o:init:33\ncreate-component.js.o:init:37 -> create-component.js.o:prepatch:43\ncreate-component.js.o:init:39 -> create-component.js.o:createComponentInstanceForVnode:178\ncreate-component.js.o:init:40 ->\ncreate-component.js.o:prepatch:46 -> lifecycle.js.o:updateChildComponent:218\ncreate-component.js.o:insert:58 -> lifecycle.js.o:callHook:319\ncreate-component.js.o:insert:67 -> scheduler.js.o:queueActivatedComponent:114\ncreate-component.js.o:insert:69 -> lifecycle.js.o:activateChildComponent:285\ncreate-component.js.o:destroy:78 -> lifecycle.js.o:anon:113\ncreate-component.js.o:destroy:80 -> lifecycle.js.o:deactivateChildComponent:303\ncreate-component.js.o:anon:86 -> Native\ncreate-component.js.o:createComponent:89 -> util.js.o:isUndef:37\ncreate-component.js.o:createComponent:96 -> util.js.o:isObject:67\ncreate-component.js.o:createComponent:97 ->\ncreate-component.js.o:createComponent:104 -> debug.js.o:warn:30\ncreate-component.js.o:createComponent:104 -> Native\ncreate-component.js.o:createComponent:111 -> util.js.o:isUndef:37\ncreate-component.js.o:createComponent:113 -> resolve-async-component.js.o:resolveAsyncComponent:27\ncreate-component.js.o:createComponent:118 -> resolve-async-component.js.o:createAsyncPlaceholder:20\ncreate-component.js.o:createComponent:126 -> init.js.o:resolveConstructorOptions:111\ncreate-component.js.o:createComponent:129 -> util.js.o:isDef:41\ncreate-component.js.o:createComponent:130 -> create-component.js.o:transformModel:206\ncreate-component.js.o:createComponent:134 -> extract-props.js.o:extractPropsFromVNodeData:10\ncreate-component.js.o:createComponent:137 -> util.js.o:isTrue:45\ncreate-component.js.o:createComponent:138 -> create-functional-component.js.o:createFunctionalComponent:81\ncreate-component.js.o:createComponent:148 -> util.js.o:isTrue:45\ncreate-component.js.o:createComponent:161 -> create-component.js.o:installComponentHooks:196\ncreate-component.js.o:createComponent:165 -> vnode.js.o:VNode:23\ncreate-component.js.o:createComponent:171 -> render-component-template.js.o:isRecyclableComponent:19\ncreate-component.js.o:createComponent:172 -> render-component-template.js.o:renderRecyclableComponentTemplate:23\ncreate-component.js.o:createComponentInstanceForVnode:189 -> util.js.o:isDef:41\ncreate-component.js.o:createComponentInstanceForVnode:193 ->\ncreate-component.js.o:transformModel:210 -> util.js.o:isDef:41\ncreate-component.js.o:transformModel:211 -> Native\n"
  },
  {
    "path": "tests/ground_truths/create-element.txt",
    "content": "create-element.js.o:anon:3 -> Native\ncreate-element.js.o:anon:9 -> Native\ncreate-element.js.o:anon:11 -> create-element.js.o:_interopRequireDefault:25\ncreate-element.js.o:anon:13 -> Native\ncreate-element.js.o:anon:15 -> create-element.js.o:_interopRequireDefault:25\ncreate-element.js.o:anon:17 -> Native\ncreate-element.js.o:anon:19 -> Native\ncreate-element.js.o:anon:21 -> Native\ncreate-element.js.o:anon:23 -> Native\ncreate-element.js.o:createElement -> Native\ncreate-element.js.o:createElement:33 -> util.js.o:isPrimitive:56\ncreate-element.js.o:createElement:38 -> util.js.o:isTrue:45\ncreate-element.js.o:createElement:41 -> create-element.js.o:_createElement:44\ncreate-element.js.o:_createElement:45 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:45 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:46 -> debug.js.o:warn:30\ncreate-element.js.o:_createElement:46 -> Native\ncreate-element.js.o:_createElement:47 -> vnode.js.o:createEmptyVNode:74\ncreate-element.js.o:_createElement:50 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:50 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:55 -> vnode.js.o:createEmptyVNode:74\ncreate-element.js.o:_createElement:58 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:58 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:58 -> util.js.o:isPrimitive:56\ncreate-element.js.o:_createElement:60 -> debug.js.o:warn:30\ncreate-element.js.o:_createElement:64 -> Native\ncreate-element.js.o:_createElement:70 -> normalize-children.js.o:normalizeChildren:42\ncreate-element.js.o:_createElement:72 -> normalize-children.js.o:simpleNormalizeChildren:29\ncreate-element.js.o:_createElement:78 -> util.js.o:noop:265\ncreate-element.js.o:_createElement:79 -> util.js.o:no:270\ncreate-element.js.o:_createElement:81 -> vnode.js.o:VNode:23\ncreate-element.js.o:_createElement:81 -> util.js.o:identity:277\ncreate-element.js.o:_createElement:82 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:84 -> create-component.js.o:createComponent:88\ncreate-element.js.o:_createElement:89 -> vnode.js.o:VNode:23\ncreate-element.js.o:_createElement:93 -> create-component.js.o:createComponent:88\ncreate-element.js.o:_createElement:95 -> Native\ncreate-element.js.o:_createElement:97 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:98 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:98 -> create-element.js.o:applyNS:106\ncreate-element.js.o:_createElement:99 -> util.js.o:isDef:41\ncreate-element.js.o:_createElement:99 -> create-element.js.o:registerDeepBindings:126\ncreate-element.js.o:_createElement:102 -> vnode.js.o:createEmptyVNode:74\ncreate-element.js.o:applyNS:113 -> util.js.o:isDef:41\ncreate-element.js.o:applyNS:116 -> util.js.o:isDef:41\ncreate-element.js.o:applyNS:116 -> util.js.o:isUndef:37\ncreate-element.js.o:applyNS:116 -> util.js.o:isTrue:45\ncreate-element.js.o:applyNS:117 -> create-element.js.o:applyNS:106\ncreate-element.js.o:registerDeepBindings:127 -> util.js.o:isObject:67\ncreate-element.js.o:registerDeepBindings:128 -> traverse.js.o:traverse:23\ncreate-element.js.o:registerDeepBindings:130 -> util.js.o:isObject:67\ncreate-element.js.o:registerDeepBindings:131 -> traverse.js.o:traverse:23\n"
  },
  {
    "path": "tests/ground_truths/ground-truth.txt",
    "content": "Template:\n<filename>:<enclosing_function_name | undefined | global>:<line_number> -> <filename>:<called_function_name | undefined>:<line_number>\n\nThe general format of a line follows the above syntax.\nAn example input and output might be:\n\nINPUT (from create-component.js.o):\n\ncomponentVNodeHooks.init();\n\n// inline hooks to be invoked on component VNodes during patch\nvar componentVNodeHooks = {\n  init: function init(vnode, hydrating, parentElm, refElm) {\n    if (vnode.componentInstance && !vnode.componentInstance._isDestroyed && vnode.data.keepAlive) {\n      // kept-alive components, treat as a patch\n      var mountedNode = vnode; // work around flow\n      componentVNodeHooks.prepatch(mountedNode, mountedNode);\n    } else {\n      ...\n\nOUTPUT:\ncreate-component.js.o:anon:29 -> create-component.js.o:init:33\ncreate-component.js.o:init:37 -> create-component.js.o:prepatch:43\ncreate-component.js.o:init:39 -> create-component.js.o:createComponentIntanceForVnode:178\n\n\nIf you are unsure where the function being call is defined, you can add and arrow without\na right side like so:\ncreate-component.js.o:init:40 ->\n\nThese will be filtered along with native functions in the final calculation\n"
  },
  {
    "path": "tests/ground_truths/patch.txt",
    "content": "patch.js.o:3 -> NativeVertex\npatch.js.o:9 -> NativeVertex\npatch.js.o:11 -> patch.js.o:_interopRequireDefault:29\npatch.js.o:13 -> NativeVertex\npatch.js.o:15 -> patch.js.o:_interopRequireDefault:29\npatch.js.o:17 -> NativeVertex\npatch.js.o:19 -> NativeVertex\npatch.js.o:21 -> NativeVertex\npatch.js.o:23 -> NativeVertex\npatch.js.o:25 -> NativeVertex\npatch.js.o:27 -> NativeVertex\npatch.js.o:43 -> vnode.js.o:VNode:23\npatch.js.o:48 -> util.js.o:isDef:41\npatch.js.o:48 -> util.js.o:isDef:41\npatch.js.o:48 -> patch.js.o:sameInputType:51\npatch.js.o:48 -> util.js.o:isTrue:45\npatch.js.o:48 -> util.js.o:isUndef:37\npatch.js.o:54 -> util.js.o:isDef:41\npatch.js.o:54 -> util.js.o:isDef:41\npatch.js.o:55 -> util.js.o:isDef:41\npatch.js.o:55 -> util.js.o:isDef:41\npatch.js.o:56 -> element.js.o:isTextInputType:67\npatch.js.o:56 -> element.js.o:isTextInputType:67\npatch.js.o:65 -> util.js.o:isDef:41\npatch.js.o:82 -> util.js.o:isDef:41\npatch.js.o:83 -> NativeVertex\npatch.js.o:89 -> vnode.js.o:VNode:23\npatch.js.o:89 -> NativeVertex\npatch.js.o:95 -> patch.js.o:102\npatch.js.o:103 ->\npatch.js.o:105 -> util.js.o:isDef:41\npatch.js.o:106 ->\npatch.js.o:111 ->\npatch.js.o:112 -> util.js.o:isRegExp:88\npatch.js.o:112 ->\npatch.js.o:113 -> util.js.o:no:270\npatch.js.o:119 -> util.js.o:isDef:41\npatch.js.o:119 -> util.js.o:isDef:41\npatch.js.o:125 -> vnode.js.o:cloneVNode:91\npatch.js.o:129 -> patch.js.o:createComponent:188\npatch.js.o:136 -> util.js.o:isDef:41\npatch.js.o:141 -> patch.js.o:isUnknownElement:110\npatch.js.o:142 -> debug.js.o:warn:30\npatch.js.o:146 ->\npatch.js.o:146 ->\npatch.js.o:147 -> patch.js.o:setScope:295\npatch.js.o:\npatch.js.o:\npatch.js.o:\npatch.js.o:\npatch.js.o:\npatch.js.o:\npatch.js.o:\npatch.js.o:\n"
  },
  {
    "path": "tests/ground_truths/vnode.txt",
    "content": "vnode.js.o:anon:3 -> Native\nvnode.js.o:anon:7 -> vnode.js.o:anon:7\nvnode.js.o:defineProperties:7 -> Native\nvnode.js.o:anon:7 -> vnode.js.o:defineProperties:7\nvnode.js.o:anon:7 -> vnode.js.o:defineProperties:7\nvnode.js.o:anon:14 -> vnode.js.o:anon:14\nvnode.js.o:VNode:24 -> vnode.js.o:_classCallCheck:12\nvnode.js.o:anon:63 -> vnode.js.o:anon:7\nvnode.js.o:createEmptyVNode:77 -> vnode.js.o:VNode:23\nvnode.js.o:createTextVNode:84 -> vnode.js.o:VNode:23\nvnode.js.o:cloneVNode:92 -> vnode.js.o:VNode:23\n"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-module.js",
    "content": "// This module directly assigns the constructor function for User to module.exports\nif (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(() => () => {return 1;});\n"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-require.js",
    "content": "// This file tests directly assigning a constructor function to module.exports\nlet arrow = require('./arrow-func-no-block-statement-module');\n\nconsole.log(arrow())\n"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-require.truth",
    "content": "arrow-func-no-block-statement-require.js:global:4 -> arrow-func-no-block-statement-module.js:anon:6\n"
  },
  {
    "path": "tests/import-export/define/define-module.js",
    "content": "// This module directly assigns the constructor function for User to module.exports\nif (typeof define !== 'function') {\n\tvar define = require('amdefine')(module);\n}\n\ndefine(function() {\n\tlet User = function(name, email) {\n\t\tthis.name = name;\n\t\tthis.email = email;\n\t};\n\treturn User;\n});\n"
  },
  {
    "path": "tests/import-export/define/define-require.js",
    "content": "// This file tests directly assigning a constructor function to module.exports\nlet user = require('./define-module');\n\nlet u = new user('random user', 'random-user@persper.org');\nconsole.log(\"%s's email is %s\", u.name, u.email);\n"
  },
  {
    "path": "tests/import-export/define/define-require.truth",
    "content": "define-require.js:global:2 -> Native\ndefine-require.js:global:4 -> define-module.js:anon:7\ndefine-require.js:global:5 -> Native\n"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies1.js",
    "content": "import { Lib } from 'es6-cyclic-dependencies2';\nexport default function double(x) {\n  return x * 2;\n}\nLib(4);\n"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies1.truth",
    "content": "es6-cyclic-dependencies1.js:global:5 -> es6-cyclic-dependencies2.js:anon:3\n"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies2.js",
    "content": "import Main from 'es6-cyclic-dependencies1';\nMain();\nvar lib = function (x) { return x; };\nexport { lib as Lib };\n"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies2.truth",
    "content": "es6-cyclic-dependencies2.js:global:2 -> es6-cyclic-dependencies1.js:double:2\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-default.js",
    "content": "export default function () { return 4; };\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-fns.js",
    "content": "export const sqrt = Math.sqrt;\nexport function square(x) {\n    return x * x;\n}\nexport function diag(x, y) {\n    return sqrt(square(x) + square(y));\n}\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-hasOwnProperty.js",
    "content": "function hasOwnProperty(obj, prop) {\n    return prop in obj;\n}\nexport { hasOwnProperty };\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-mixed.js",
    "content": "export default function () {\n    return 9;\n}\nexport function each() {\n    return 7;\n}\nexport { each as forEach };\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-default.js",
    "content": "import myFunc from 'es6-export-default';\nmyFunc();\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-default.truth",
    "content": "es6-import-default.js:global:2 -> es6-export-default.js:anon:1\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-entire.js",
    "content": "import * as lib from 'es6-export-fns';\nconsole.log(lib.square(11)); // 121\nconsole.log(lib.diag(4, 3)); // 5\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-entire.truth",
    "content": "es6-import-entire.js:global:2 -> Native\nes6-import-entire.js:global:2 -> es6-export-fns.js:square:2\nes6-import-entire.js:global:3 -> Native\nes6-import-entire.js:global:3 -> es6-export-fns.js:diag:5\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-hasOwnProperty.js",
    "content": "import { hasOwnProperty } from 'es6-export-hasOwnProperty';\nconsole.log(hasOwnProperty({'prop': true}, 'prop'));\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-hasOwnProperty.truth",
    "content": "es6-import-hasOwnProperty.js:global:2 -> es6-export-hasOwnProperty.js:hasOwnProperty:1\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-mixed.js",
    "content": "import _, { each } from 'es6-export-mixed';\n\n_();\neach();\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-mixed.truth",
    "content": "es6-import-mixed.js:global:3 -> es6-export-mixed.js:anon:1\nes6-import-mixed.js:global:4 -> es6-export-mixed.js:each:4\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-named.js",
    "content": "import { square, diag } from 'es6-export-fns';\nconsole.log(square(11)); // 121\nconsole.log(diag(4, 3)); // 5\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-named.truth",
    "content": "es6-import-named.js:global:2 -> Native\nes6-import-named.js:global:2 -> es6-export-fns.js:square:2\nes6-import-named.js:global:3 -> Native\nes6-import-named.js:global:3 -> es6-export-fns.js:diag:5\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-redirect.js",
    "content": "import {login, logout, addProject, updateProject, executeSearch} from 'redirect/index';\n// import {updateProject} from 'redirect/index';\nlogin(4);\nlogout(8, 0);\nupdateProject();\naddProject();\nexecuteSearch(1, 2, 3);\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-redirect.truth",
    "content": "es6-import-redirect.js:global:3 -> auth.js:login:1\nes6-import-redirect.js:global:4 -> auth.js:logout:5\nes6-import-redirect.js:global:5 -> project.js:update:5\nes6-import-redirect.js:global:6 -> project.js:addProject:1\nes6-import-redirect.js:global:7 -> search.js:executeSearch:1\n"
  },
  {
    "path": "tests/import-export/es6/redirect/auth.js",
    "content": "function login(x) {\n  return x;\n}\n\nfunction logout(x, y) {\n  return x + y;\n}\nexport { login, logout };\n"
  },
  {
    "path": "tests/import-export/es6/redirect/index.js",
    "content": "export {login, logout} from './auth';\nexport {addProject, updateProject} from './project';\nexport {executeSearch} from './search';\n"
  },
  {
    "path": "tests/import-export/es6/redirect/project.js",
    "content": "function addProject() {\n  return 'whooplah';\n}\n\nfunction update() {\n  return 'dooplah';\n}\n\nexport { addProject, update as updateProject };\n"
  },
  {
    "path": "tests/import-export/es6/redirect/search.js",
    "content": "function executeSearch(x, y, z) {\n  return x * y * z;\n}\nexport { executeSearch }\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-module.js",
    "content": "// This module directly assigns the constructor function for User to module.exports\nlet User = function(name, email) {\n\tthis.name = name;\n\tthis.email = email;\n};\n\nmodule.exports = User;\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-module2.js",
    "content": "let x = 5;\nlet addX = function(value) {\n\treturn value + x;\n};\n\nmodule.exports.x = x;\nmodule.exports.addX = addX;\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require.js",
    "content": "// This file tests directly assigning a constructor function to module.exports\nlet user = require('./module-exports-module');\n\nlet u = new user('random user', 'random-user@persper.org');\nconsole.log(\"%s's email is %s\", u.name, u.email);\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require.truth",
    "content": "module-exports-require.js:global:2 -> Native\nmodule-exports-require.js:global:4 -> module-exports-module.js:anon:2\nmodule-exports-require.js:global:5 -> Native\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require2.js",
    "content": "// This file tests the most common usage of exports/require\nlet m1 = require('./module-exports-module2');\nconsole.log(\"Adding %d to 10 gives us %d\", m1.x, m1.addX(10));\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require2.truth",
    "content": "module-exports-require2.js:global:2 -> Native\nmodule-exports-require2.js:global:3 -> Native\nmodule-exports-require2.js:global:3 -> module-exports-module2.js:anon:2\n"
  },
  {
    "path": "tests/jest/graph.test.js",
    "content": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundation\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *******************************************************************************/\n\nconst graph = require('../../src/graph');\nconst flowgraph = require('../../src/flowgraph');\nconst astutil = require('../../src/astutil');\n/*\ntest('TEST FORMAT', () => {\n  const G = new graph.Graph();\n\n  var nodeA = new Node('A');\n  var nodeB = new Node('B');\n\n});\n*/\n\nfn1 = {\n            \"type\": \"FunctionDeclaration\",\n            \"id\": {\n                \"type\": \"Identifier\",\n                \"name\": \"f\",\n                \"range\": [\n                    9,\n                    10\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 1,\n                        \"column\": 9\n                    },\n                    \"end\": {\n                        \"line\": 1,\n                        \"column\": 10\n                    }\n                }\n            },\n            \"params\": [],\n            \"body\": {\n                \"type\": \"BlockStatement\",\n                \"body\": [],\n                \"range\": [\n                    13,\n                    15\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 1,\n                        \"column\": 13\n                    },\n                    \"end\": {\n                        \"line\": 1,\n                        \"column\": 15\n                    }\n                }\n            },\n            \"generator\": false,\n            \"expression\": false,\n            \"async\": false,\n            \"range\": [\n                0,\n                15\n            ],\n            \"loc\": {\n                \"start\": {\n                    \"line\": 1,\n                    \"column\": 0\n                },\n                \"end\": {\n                    \"line\": 1,\n                    \"column\": 15\n                }\n            }\n        }\nfn2 = {\n            \"type\": \"FunctionDeclaration\",\n            \"id\": {\n                \"type\": \"Identifier\",\n                \"name\": \"g\",\n                \"range\": [\n                    10,\n                    11\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 2,\n                        \"column\": 9\n                    },\n                    \"end\": {\n                        \"line\": 2,\n                        \"column\": 10\n                    }\n                }\n            },\n            \"params\": [],\n            \"body\": {\n                \"type\": \"BlockStatement\",\n                \"body\": [],\n                \"range\": [\n                    14,\n                    16\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 2,\n                        \"column\": 13\n                    },\n                    \"end\": {\n                        \"line\": 2,\n                        \"column\": 15\n                    }\n                }\n            },\n            \"generator\": false,\n            \"expression\": false,\n            \"async\": false,\n            \"range\": [\n                1,\n                16\n            ],\n            \"loc\": {\n                \"start\": {\n                    \"line\": 2,\n                    \"column\": 0\n                },\n                \"end\": {\n                    \"line\": 2,\n                    \"column\": 15\n                }\n            }\n        }\n\nfn3 = {\n            \"type\": \"FunctionDeclaration\",\n            \"id\": {\n                \"type\": \"Identifier\",\n                \"name\": \"h\",\n                \"range\": [\n                    11,\n                    12\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 3,\n                        \"column\": 9\n                    },\n                    \"end\": {\n                        \"line\": 3,\n                        \"column\": 10\n                    }\n                }\n            },\n            \"params\": [],\n            \"body\": {\n                \"type\": \"BlockStatement\",\n                \"body\": [],\n                \"range\": [\n                    15,\n                    17\n                ],\n                \"loc\": {\n                    \"start\": {\n                        \"line\": 3,\n                        \"column\": 13\n                    },\n                    \"end\": {\n                        \"line\": 3,\n                        \"column\": 15\n                    }\n                }\n            },\n            \"generator\": false,\n            \"expression\": false,\n            \"async\": false,\n            \"range\": [\n                2,\n                17\n            ],\n            \"loc\": {\n                \"start\": {\n                    \"line\": 3,\n                    \"column\": 0\n                },\n                \"end\": {\n                    \"line\": 3,\n                    \"column\": 15\n                }\n            }\n        }\n\nfn1.attr = {}\nfn2.attr = {}\nfn3.attr = {}\n\nfn_vertex1 = flowgraph.funcVertex(fn1);\nfn_vertex2 = flowgraph.funcVertex(fn2);\nfn_vertex3 = flowgraph.funcVertex(fn3);\n\nfv1 = fn_vertex1;\nfv2 = fn_vertex2;\nfv3 = fn_vertex3;\n\ntest('Add edge between two nodes and check graph has nodes', () => {\n  const G = new graph.Graph();\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.hasNode(fv1)).toBe(true);\n  expect(G.hasNode(fv2)).toBe(true);\n});\n\ntest('Add edge between two nodes and check graph has edge between them', () => {\n  const G = new graph.Graph();\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.hasEdge(fv1, fv2)).toBe(true);\n});\n\ntest('Add edge, remove it and verify it is removed', () => {\n  const G = new graph.Graph();\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.removeEdge(fv1, fv2)).toBe(true);\n\n  expect(G.hasEdge(fv1, fv2)).toBe(false);\n});\n\ntest('Add edge, remove one of the nodes and verify it is removed', () => {\n  const G = new graph.Graph();\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.removeNode(fv2)).toBe(true);\n\n  expect(G.hasNode(fv2)).toBe(false);\n  expect(G.hasEdge(fv1, fv2)).toBe(false);\n});\n\ntest('Add edge and verify the reverse direction edge is not in the graph', () => {\n  const G = new graph.Graph();\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.hasEdge(fv2, fv1)).toBe(false);\n});\n\ntest('Add many edges, remove the nodes and verify they are all removed', () => {\n  const G = new graph.Graph();\n\n  var nodes = [];\n\n  function make_pp(s) {\n    return function() {\n      return 'Func(' + s + ')'\n    }\n  }\n\n  for (var i = 0; i < 1000; ++i)\n    nodes[i] = {\n      'name': i.toString(),\n      'type': 'FuncVertex',\n      'attr': {pp: make_pp(i.toString())  },\n    };\n\n  for (var i = 0; i < 999; ++i)\n    G.addEdge(nodes[i], nodes[i + 1]);\n\n  for (var i = 0; i < 1000; ++i)\n    G.removeNode(nodes[i]);\n\n  for (var i = 0; i < 1000; ++i)\n    expect(G.hasNode(nodes[i])).toBe(false);\n\n  for (var i = 0; i < 999; ++i)\n    expect(G.hasEdge(nodes[i], nodes[i + 1])).toBe(false);\n});\n\ntest('Add many edges, remove the edges and verify they are all removed', () => {\n  const G = new graph.Graph();\n\n  var nodes = [];\n\n  function make_pp(s) {\n    return function() {\n      return 'Func(' + s + ')'\n    }\n  }\n\n  for (var i = 0; i < 1000; ++i)\n    nodes[i] = {\n      'name': i.toString(),\n      'type': 'FuncVertex',\n      'attr': {pp: make_pp(i.toString())  },\n    };\n\n  for (var i = 0; i < 999; ++i)\n    G.addEdge(nodes[i], nodes[i + 1]);\n\n  for (var i = 0; i < 999; ++i)\n    G.removeEdge(nodes[i], nodes[i + 1]);\n\n  for (var i = 0; i < 1000; ++i)\n    expect(G.hasNode(nodes[i])).toBe(true);\n\n  for (var i = 0; i < 999; ++i)\n    expect(G.hasEdge(nodes[i], nodes[i + 1])).toBe(false);\n});\n\ntest('Add nodes and verify they were added', () => {\n  const G = new graph.Graph();\n\n  G.addNode(fv1);\n  G.addNode(fv2);\n  G.addNode(fv3);\n\n  expect(G.hasNode(fv1)).toBe(true);\n  expect(G.hasNode(fv2)).toBe(true);\n  expect(G.hasNode(fv3)).toBe(true);\n});\n\ntest('Add nodes, remove them and verify they were removed', () => {\n  const G = new graph.Graph();\n\n  G.addNode(fv1);\n  G.addNode(fv2);\n  G.addNode(fv3);\n\n  G.removeNode(fv1);\n  G.removeNode(fv2);\n  G.removeNode(fv3);\n\n  expect(G.hasNode(fv1)).toBe(false);\n  expect(G.hasNode(fv2)).toBe(false);\n  expect(G.hasNode(fv3)).toBe(false);\n});\n\ntest('Add nodes, add edge, verify graph has edges and nodes', () => {\n  const G = new graph.Graph();\n\n  G.addNode(fv1);\n  G.addNode(fv2);\n\n  G.addEdge(fv1, fv2);\n\n  expect(G.hasNode(fv1)).toBe(true);\n  expect(G.hasNode(fv2)).toBe(true);\n\n  expect(G.hasEdge(fv1, fv2)).toBe(true);\n});\n\ntest('Add nodes, applies function to all nodes and verifies changes are made', () => {\n  const G = new graph.Graph();\n\n  G.addNode(fv1);\n  G.addNode(fv2);\n  G.addNode(fv3);\n\n  G.iterNodes((nd) => { nd.func.id.name = nd.func.id.name.toLowerCase(); });\n\n  expect(fv1.func.id.name).toBe('f');\n  expect(fv2.func.id.name).toBe('g');\n  expect(fv3.func.id.name).toBe('h');\n});\n"
  },
  {
    "path": "tests/jest/linkedList.test.js",
    "content": "\nconst { LinkedList } = require('../../src/linkedList');\n\ntest('test LinkedList', () => {\n    let ll = new LinkedList();\n    expect(ll.isEmpty()).toBe(true);\n    ll.add(10);\n    expect(ll.size).toBe(1);\n    ll.add(20);\n    ll.add(30);\n    ll.add(40);\n    ll.add(50);\n    expect(ll.size).toBe(5);\n    expect(ll.has(30)).toBe(true);\n    expect(ll.has(10)).toBe(true);\n    ll.remove(30);\n    ll.remove(10);\n    expect(ll.has(30)).toBe(false);\n    expect(ll.has(10)).toBe(false);\n    expect(ll.size).toBe(3);\n    let lst = [];\n    for (let lnode of ll) {\n        lst.push(lnode);\n    }\n    expect(lst).toStrictEqual([50, 40, 20]);\n    ll.remove(50);\n    ll.remove(40);\n    ll.remove(20);\n    expect(ll.size).toBe(0);\n    expect(ll.isEmpty()).toBe(true);\n});\n"
  },
  {
    "path": "tests/limits/history.js",
    "content": "// This file illustrates one of the limitations of the call graph algorithm\n// Only func2 is called in main function,\n// but the algorithm can't rule out the possibility that func1 is called too\nfunction main () {\n    let a = function func1 () { console.log('func1 is called!'); };\n    let b = a;\n    b = function func2() { console.log('func2 is called!'); };\n    a = b;\n    a(); // func2 is called\n    b(); // func2 is called\n}\n\nmain();\n"
  },
  {
    "path": "tests/limits/history.truth",
    "content": "history.js:func1:5 -> Native\nhistory.js:func1:7 -> Native\nhistory.js:main:9 -> history.js:func2:7\nhistory.js:main:10 -> history.js:func2:7\nhistory.js:global:13 -> history.js:main:4\n"
  },
  {
    "path": "tests/limits/overload.js",
    "content": "function f() {\n  return 5;\n}\n\nf();\n\nfunction f(x) {\n  return x;\n}\n\nf(4);\n"
  },
  {
    "path": "tests/limits/overload.truth",
    "content": "overload.js:global:5 -> overload.js:f:1\noverload.js:global:11 -> overload.js:f:7\n"
  },
  {
    "path": "tests/process.py",
    "content": "#!/usr/bin/python3\n\n# Author: Alex Stennet\n# Description: Provides a testing framework for the call graph genereation\n#\n# An example of how to run:\n#   ./process.py basics/arrow.js basics/arrow.truth\n\n\nimport sys\nfrom pathlib import Path\nimport re\nfrom required_files import collect_requires\nfrom callgraph import callgraph_formatted\n\n\ndef get_output(test_file):\n    # Recursively descend through require's to find all files that\n    # must be included to fill the callgraph\n    required_files = collect_requires(Path(test_file).resolve())\n    strd_files = [str(rf) for rf in required_files]\n\n    # Run the javascript call graph program and capture the output\n    output = callgraph_formatted(strd_files, keep=required_files[0].name,\n                                 natives=False)\n\n    return output\n\n\ndef precision_recall(test_file, expected_output):\n    fo = get_output(test_file)\n\n    # Reading in expected output file and comparing with output\n    f = open(expected_output)\n\n    lines = [line.rstrip('\\n') for line in f if 'Native' not in line]\n\n    output_lines = set(fo)\n    expected_lines = set(lines)\n\n    intersection = output_lines & expected_lines\n    difference = output_lines ^ expected_lines\n\n    if len(difference) != 0:\n        missing_output = expected_lines - output_lines\n        extra_output = output_lines - expected_lines\n\n        print()\n\n        for l in intersection:\n            print('\\t' + l)\n\n        for l in extra_output:\n            print('\\t+', l)\n\n        for l in missing_output:\n            print('\\t-', l)\n\n    if len(output_lines) > 0:\n        precision = 100 * len(intersection) // len(output_lines)\n    else:\n        precision = 0\n\n    recall = 100*len(intersection) // len(expected_lines)\n\n    return precision, recall\n\n\nif __name__ == \"__main__\":\n    assert len(sys.argv) == 3,\\\n           \"Incorrect number of arguments: process.py FILENAME TEST_FILE\"\n\n    precision_recall(sys.argv[1], sys.argv[2])\n"
  },
  {
    "path": "tests/required_files.py",
    "content": "import re\nfrom pathlib import Path\n\nreg1 = re.compile(\"require\\\\(\\'(.*)\\'\\\\)\")\nreg2 = re.compile(\"import .* from \\'(.*)\\'\")\nreg3 = re.compile(\"import \\'(.*)\\'(?! from)\")\nreg4 = re.compile(\"export .* from \\'(.*)\\'\")\n\n\ndef match_to_path(match):\n    if match.endswith('.js') or match.endswith('.ts') or match.endswith('.vue'):\n        return match\n    else:\n        return match + '.js'\n\n\ndef get_requires(path):\n    \"\"\" Returns list of imports in path \"\"\"\n    f = path.open()\n    text = f.read()\n    f.close()\n\n    matches1 = reg1.findall(text)\n    matches2 = reg2.findall(text)\n    matches3 = reg3.findall(text)\n    matches4 = reg4.findall(text)\n\n    # lst1 = [m + '.js' for m in matches1]\n    # lst2 = [m + '.js' for m in matches2]\n    # lst3 = [m + '.js' for m in matches3]\n    # lst4 = [m + '.js' for m in matches4]\n\n    lst1 = [match_to_path(m) for m in matches1]\n    lst2 = [match_to_path(m) for m in matches2]\n    lst3 = [match_to_path(m) for m in matches3]\n    lst4 = [match_to_path(m) for m in matches4]\n\n    lst = lst1 + lst2 + lst3 + lst4\n\n    return lst\n\n\ndef collect_requires(path):\n    \"\"\" Recursively descends imports and returns all imported files \"\"\"\n    read_files = []\n    unread_files = [path]\n\n    while unread_files:\n        uf = unread_files.pop(0)\n\n        if uf in read_files:\n            continue\n\n        read_files.append(uf.resolve())\n        required_files = get_requires(uf)\n\n        for rf in required_files:\n            rp = uf.parent.joinpath(rf)\n            if rp and rp.exists():\n                unread_files.append(rp.resolve())\n\n    return read_files\n"
  },
  {
    "path": "tests/test.py",
    "content": "#!/usr/bin/python3\n\nimport os, sys, glob, time\nfrom os.path import isfile, join, dirname, isdir, basename\nfrom process import precision_recall\n\n# -------------- Configuration --------------\n\n# Only scan the following directories for test cases\ntest_dirs = ['basics',\n             'unexpected',\n             'classes',\n             'es6',\n             'import-export/define',\n             'import-export/es6',\n             'import-export/module.exports',\n             'typescript',\n             'vue']\n\n# Only consider test cases in the following languages\nlangs = ['*.js', '*.ts', '*.vue']\n\n# -------------------------------------------\n\nprint()\nprint('RUNNING REGRESSION TESTS')\n\ntest_root_dir = dirname(sys.argv[0])\nnum_passed = 0\nnum_failed = 0\n\n\ndef find_truth_file(test_file):\n    truth_file = test_file.rsplit('.', 1)[0] + '.truth'\n    if os.path.isfile(truth_file):\n        return truth_file\n    else:\n        return None\n\nstart = time.time()\n\nfor d in test_dirs:\n    print('\\n' + '='*5, d, '='*5 + '\\n')\n    d = join(test_root_dir, d)\n\n    for lang in langs:\n        for test_file in glob.iglob(d + '/**/' + lang, recursive=True):\n            truth_file = find_truth_file(test_file)\n            if not truth_file:\n                continue\n            precision, recall = precision_recall(test_file, truth_file)\n\n            print(basename(test_file), end='')\n            if precision == 100 and recall == 100:\n                print('\\r' + test_file + ' ✓')\n                num_passed += 1\n            else:\n                print('\\rFAILED: ' + test_file + ' ❌\\n')\n                num_failed += 1\n\nend = time.time()\n\nprint()\nprint('Number passed: ' + str(num_passed))\nprint('Number failed: ' + str(num_failed))\nprint('Total time: ' + str(end - start))\n\nif num_failed > 0:\n    exit(1)\n"
  },
  {
    "path": "tests/typescript/simple.truth",
    "content": "simple.ts:global:7 -> simple.ts:greeter:1\n"
  },
  {
    "path": "tests/typescript/simple.ts",
    "content": "function greeter(person: string) {\n    return \"Hello, \" + person;\n}\n\nlet user = \"Jane User\";\n\ndocument.body.innerHTML = greeter(user);\n"
  },
  {
    "path": "tests/unexpected/stringiterator.js",
    "content": "// this code is extracted from Libraries/vendor/core/toIterator.js of the following commit\n// https://github.com/facebook/react-native/commit/a15603d8f1ecdd673d80be318293cee53eb4475d\nclass StringIterator {\n  // 21.1.5.1 CreateStringIterator Abstract Operation\n  constructor(string) {\n    if (typeof string !== 'string') {\n      throw new TypeError('Object is not a string');\n    }\n    this._iteratedString = string;\n    this._nextIndex = 0;\n  }\n\n  // 21.1.5.2.1 %StringIteratorPrototype%.next()\n  next() {\n    if (!this instanceof StringIterator) {\n      throw new TypeError('Object is not a StringIterator');\n    }\n\n    if (this._iteratedString == null) {\n      return createIterResultObject(undefined, true);\n    }\n\n    var index = this._nextIndex;\n    var s = this._iteratedString;\n    var len = s.length;\n\n    if (index >= len) {\n      this._iteratedString = undefined;\n      return createIterResultObject(undefined, true);\n    }\n\n    var ret;\n    var first = s.charCodeAt(index);\n\n    if (first < 0xD800 || first > 0xDBFF || index + 1 === len) {\n      ret = s[index];\n    } else {\n      var second = s.charCodeAt(index + 1);\n      if (second < 0xDC00 || second > 0xDFFF) {\n        ret = s[index];\n      } else {\n        ret = s[index] + s[index + 1];\n      }\n    }\n\n    this._nextIndex = index + ret.length;\n\n    return createIterResultObject(ret, false);\n  }\n\n  // 21.1.5.2.2 %StringIteratorPrototype%[@@ITERATOR_SYMBOL]()\n  '@@iterator'() {\n    return this;\n  }\n}\n\nfunction createIterResultObject(value, done) {\n  return {value: value, done: done};\n}\n"
  },
  {
    "path": "tests/unexpected/stringiterator.truth",
    "content": "stringiterator.js:next:48 -> stringiterator.js:createIterResultObject:57\nstringiterator.js:next:29 -> stringiterator.js:createIterResultObject:57\nstringiterator.js:next:20 -> stringiterator.js:createIterResultObject:57\n"
  },
  {
    "path": "tests/unhandled/classes/class-compiled.js",
    "content": "\"use strict\";\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar Rectangle = function () {\n  function Rectangle(height, width) {\n    _classCallCheck(this, Rectangle);\n\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n\n\n  _createClass(Rectangle, [{\n    key: \"calcArea\",\n\n    // Method\n    value: function calcArea() {\n      return this.height * this.width;\n    }\n  }, {\n    key: \"area\",\n    get: function get() {\n      return this.calcArea();\n    }\n  }]);\n\n  return Rectangle;\n}();\n\nvar square = new Rectangle(10, 10);\n\nconsole.log(square.area);\n\n"
  },
  {
    "path": "tests/unhandled/classes/class-compiled.truth",
    "content": "class-compiled.js:global:3 -> class-compiled.js:anon:3\nclass-compiled.js:defineProperties:3 -> Native\nclass-compiled.js:anon:3 -> class-compiled.js:defineProperties:3\nclass-compiled.js:anon:3 -> class-compiled.js:defineProperties:3\nclass-compiled.js:_classCallCheck:5 -> Native\nclass-compiled.js:global:7 -> class-compiled.js:anon:7\nclass-compiled.js:Rectangle:9 -> class-compiled.js:_classCallCheck:5\nclass-compiled.js:anon:17 -> class-compiled.js:_createClass:3\nclass-compiled.js:get:27 -> class-compiled.js:calcArea:21\nclass-compiled.js:global:34 -> class-compiled.js:Rectangle:8\nclass-compiled.js:global:36 -> Native\nclass-compiled.js:global:36 -> class-compiled.js:get:26\n"
  },
  {
    "path": "tests/unhandled/classes/class-compiled2.js",
    "content": "\"use strict\";\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar Rectangle = function () {\n  function Rectangle(height, width) {\n    _classCallCheck(this, Rectangle);\n\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n\n\n  _createClass(Rectangle, [{\n    key: \"calcArea\",\n\n    // Method\n    value: function calcArea() {\n      return this.height * this.width;\n    }\n  }, {\n    key: \"area\",\n    get: function get() {\n      return this.calcArea();\n    }\n  }]);\n\n  return Rectangle;\n}();\n\nvar square = new Rectangle(10, 10);\n\nconsole.log(square.calcArea());\n\n"
  },
  {
    "path": "tests/unhandled/classes/class-compiled2.truth",
    "content": "class-compiled2.js:global:3 -> class-compiled2.js:anon:3\nclass-compiled2.js:defineProperties:3 -> Native\nclass-compiled2.js:anon:3 -> class-compiled2.js:defineProperties:3\nclass-compiled2.js:anon:3 -> class-compiled2.js:defineProperties:3\nclass-compiled2.js:_classCallCheck:5 -> Native\nclass-compiled2.js:global:7 -> class-compiled2.js:anon:7\nclass-compiled2.js:Rectangle:9 -> class-compiled2.js:_classCallCheck:5\nclass-compiled2.js:anon:17 -> class-compiled2.js:_createClass:3\nclass-compiled2.js:get:27 -> class-compiled2.js:calcArea:21\nclass-compiled2.js:global:34 -> class-compiled2.js:Rectangle:8\nclass-compiled2.js:global:36 -> Native\nclass-compiled2.js:global:36 -> class-compiled2.js:calcArea:21\n"
  },
  {
    "path": "tests/unhandled/classes/class-getter.js",
    "content": "class Rectangle {\n  constructor(height, width) {\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n  get area() {\n    return this.calcArea();\n  }\n  // Method\n  calcArea() {\n    return this.height * this.width;\n  }\n}\n\nconst square = new Rectangle(10, 10);\n\nconsole.log(square.area);\n"
  },
  {
    "path": "tests/unhandled/classes/class-getter.truth",
    "content": "class-getter.js:area:8 -> class-getter.js:calcArea:11\nclass-getter.js:global:16 -> class-getter.js:constructor:2\nclass-getter.js:global:18 -> Native\nclass-getter.js:global:18 -> class-getter.js:area:7\n"
  },
  {
    "path": "tests/unhandled/limits/history.js",
    "content": "// This file illustrates one of the limitations of the call graph algorithm\n// Only func2 is called in main function,\n// but the algorithm can't rule out the possibility that func1 is called too\nfunction main () {\n    let a = function func1 () { console.log('func1 is called!'); };\n    let b = a;\n    b = function func2() { console.log('func2 is called!'); };\n    a = b;\n    a(); // func2 is called\n    b(); // func2 is called\n}\n\nmain();\n"
  },
  {
    "path": "tests/unhandled/limits/history.truth",
    "content": "history.js:func1:5 -> Native\nhistory.js:func1:7 -> Native\nhistory.js:main:9 -> history.js:func2:7\nhistory.js:main:10 -> history.js:func2:7\nhistory.js:global:13 -> history.js:main:4\n"
  },
  {
    "path": "tests/unhandled/limits/overload.js",
    "content": "function f() {\n  return 5;\n}\n\nf();\n\nfunction f(x) {\n  return x;\n}\n\nf(4);\n"
  },
  {
    "path": "tests/unhandled/limits/overload.truth",
    "content": "overload.js:global:5 -> overload.js:f:1\noverload.js:global:11 -> overload.js:f:7\n"
  },
  {
    "path": "tests/vue/TodoList.truth",
    "content": "TodoList.vue:addTodo:62 -> example.vue:data:10\nTodoList.vue:addTodo:62 -> TodoList.vue:data:33\n"
  },
  {
    "path": "tests/vue/TodoList.vue",
    "content": "<template>\n    <div>\n        <BaseInputText \n            v-model=\"newTodoText\"\n            placeholder=\"New todo\"\n            @keydown.enter=\"addTodo\"\n        />\n        <ul v-if=\"todos.length\">\n            <TodoListItem\n                v-for=\"todo in todos\"\n                :key=\"todo.id\"\n                :todo=\"todo\"\n                @remove=\"removeTodo\"\n            />\n        </ul>\n        <p v-else>\n            Nothing left in the list. Add a new todo in the input above.\n        </p>\n    </div>\n</template>\n\n<script>\nimport BaseInputText from './BaseInputText.vue'\nimport TodoListItem from './TodoListItem.vue'\nimport HelloWorld from './example.vue'\n\nlet nextTodoId = 1\n\nexport default {\n    components: {\n        BaseInputText, TodoListItem\n    },\n  data () {\n    return {\n            newTodoText: '',\n      todos: [\n                {\n                    id: nextTodoId++,\n                    text: 'Learn Vue'\n                },\n                {\n                    id: nextTodoId++,\n                    text: 'Learn about single-file components'\n                },\n                {\n                    id: nextTodoId++,\n                    text: 'Fall in love'\n                }\n            ]\n    }\n  },\n    methods: {\n        addTodo () {\n            const trimmedText = this.newTodoText.trim()\n            if (trimmedText) {\n                this.todos.push({\n                    id: nextTodoId++,\n                    text: trimmedText\n                })\n                this.newTodoText = ''\n            }\n            HelloWorld.data();\n        },\n        removeTodo (idToRemove) {\n            this.todos = this.todos.filter(todo => {\n                return todo.id !== idToRemove\n            })\n        }\n    }\n}\n</script>"
  },
  {
    "path": "tests/vue/example.vue",
    "content": "<template lang=\"pug\">\n.hello\n  h1 {{ msg }}\n</template>\n \n<script lang=\"js\">\nexport default {\n  name: 'Hello',\n \n  data () {\n    return {\n      msg: 'Hello World!'\n    }\n  }\n \n}\n</script>\n \n<style>\nh1 {\n  font-weight: normal;\n}\n</style>\n"
  }
]