Full Code of Persper/js-callgraph for AI

master 7abc6bb04fed cached
184 files
1.1 MB
305.2k tokens
422 symbols
1 requests
Download .txt
Showing preview only (1,153K chars total). Download the full file or copy to clipboard to get everything.
Repository: Persper/js-callgraph
Branch: master
Commit: 7abc6bb04fed
Files: 184
Total size: 1.1 MB

Directory structure:
gitextract_ps1zfdc6/

├── .eslintrc
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── index.js
├── input-scripts/
│   ├── coolclock/
│   │   ├── coolclock.js
│   │   ├── excanvas.js
│   │   └── moreskins.js
│   ├── flotr/
│   │   ├── flotr-0.2.0-alpha.js
│   │   ├── flotr.debug-0.2.0-alpha.js
│   │   └── lib/
│   │       ├── base64.js
│   │       ├── canvas2image.js
│   │       ├── canvastext.js
│   │       ├── excanvas.js
│   │       └── prototype-1.6.0.2.js
│   ├── fullcalendar/
│   │   ├── fullcalendar/
│   │   │   ├── fullcalendar.css
│   │   │   ├── fullcalendar.js
│   │   │   ├── fullcalendar.print.css
│   │   │   └── gcal.js
│   │   └── lib/
│   │       └── jquery-2.1.0.js
│   └── simple-scripts/
│       ├── function_function.js
│       ├── functioncall-arithmetic.js
│       ├── jQuery.js
│       ├── or_function.js
│       └── use_before_definition.js
├── js-callgraph.js
├── package.json
├── saveSvgAsPng.js
├── scripts/
│   ├── install-hooks
│   └── pre-commit
├── src/
│   ├── astutil.js
│   ├── bindings.js
│   ├── bitset.js
│   ├── callbackCounter.js
│   ├── callgraph.js
│   ├── dftc.js
│   ├── diagnostics.js
│   ├── flowgraph.js
│   ├── graph.js
│   ├── harness.js
│   ├── input-2.js
│   ├── linkedList.js
│   ├── module.js
│   ├── natives.js
│   ├── numset.js
│   ├── olist.js
│   ├── pessimistic.js
│   ├── requireJsGraph.js
│   ├── runner.js
│   ├── semioptimistic.js
│   ├── set.js
│   ├── srcPreprocessor.js
│   ├── symtab.js
│   ├── tests.js
│   ├── underscore.js
│   └── utils.js
└── tests/
    ├── README.md
    ├── basics/
    │   ├── arrow.js
    │   ├── arrow.truth
    │   ├── assignment.js
    │   ├── assignment.truth
    │   ├── global-as-prop.js
    │   ├── global-as-prop.truth
    │   ├── local-is-fine.js
    │   ├── local-is-fine.truth
    │   ├── method-def.js
    │   └── method-def.truth
    ├── callgraph.py
    ├── classes/
    │   ├── anonymous-class.js
    │   ├── basic-class.js
    │   ├── basic-class.truth
    │   ├── basic-class2.js
    │   ├── basic-class2.truth
    │   ├── class-expression1.js
    │   ├── class-expression1.truth
    │   ├── class-expression2.js
    │   ├── class-expression2.truth
    │   ├── class.js
    │   ├── class.truth
    │   ├── export-class-expression1.js
    │   ├── export-class-expression2.js
    │   ├── import-anonymous-class.js
    │   ├── import-anonymous-class.truth
    │   ├── import-class-expression1.js
    │   ├── import-class-expression1.truth
    │   ├── import-class-expression2.js
    │   ├── import-class-expression2.truth
    │   ├── outer-fn.js
    │   └── outer-fn.truth
    ├── creating-vue-compiled.txt
    ├── es6/
    │   ├── array-pattern.js
    │   ├── array-pattern.truth
    │   ├── array-pattern2.js
    │   ├── array-pattern2.truth
    │   ├── array-pattern3.js
    │   ├── array-pattern3.truth
    │   ├── array-pattern4.js
    │   ├── array-pattern4.truth
    │   ├── binding-pattern-global.js
    │   ├── binding-pattern-global.truth
    │   ├── destructured-parameter.js
    │   ├── destructured-parameter.truth
    │   ├── destructured-parameter2.js
    │   ├── destructured-parameter2.truth
    │   ├── destructured-parameter3.js
    │   ├── destructured-parameter3.truth
    │   ├── lib.js
    │   ├── main.js
    │   ├── main.truth
    │   ├── object-pattern.js
    │   ├── object-pattern.truth
    │   ├── object-pattern2.js
    │   ├── object-pattern2.truth
    │   ├── object-pattern3.js
    │   └── object-pattern3.truth
    ├── ground_truths/
    │   ├── create-component.txt
    │   ├── create-element.txt
    │   ├── ground-truth.txt
    │   ├── patch.txt
    │   └── vnode.txt
    ├── import-export/
    │   ├── define/
    │   │   ├── arrow-func-no-block-statement-module.js
    │   │   ├── arrow-func-no-block-statement-require.js
    │   │   ├── arrow-func-no-block-statement-require.truth
    │   │   ├── define-module.js
    │   │   ├── define-require.js
    │   │   └── define-require.truth
    │   ├── es6/
    │   │   ├── es6-cyclic-dependencies1.js
    │   │   ├── es6-cyclic-dependencies1.truth
    │   │   ├── es6-cyclic-dependencies2.js
    │   │   ├── es6-cyclic-dependencies2.truth
    │   │   ├── es6-export-default.js
    │   │   ├── es6-export-fns.js
    │   │   ├── es6-export-hasOwnProperty.js
    │   │   ├── es6-export-mixed.js
    │   │   ├── es6-import-default.js
    │   │   ├── es6-import-default.truth
    │   │   ├── es6-import-entire.js
    │   │   ├── es6-import-entire.truth
    │   │   ├── es6-import-hasOwnProperty.js
    │   │   ├── es6-import-hasOwnProperty.truth
    │   │   ├── es6-import-mixed.js
    │   │   ├── es6-import-mixed.truth
    │   │   ├── es6-import-named.js
    │   │   ├── es6-import-named.truth
    │   │   ├── es6-import-redirect.js
    │   │   ├── es6-import-redirect.truth
    │   │   └── redirect/
    │   │       ├── auth.js
    │   │       ├── index.js
    │   │       ├── project.js
    │   │       └── search.js
    │   └── module.exports/
    │       ├── module-exports-module.js
    │       ├── module-exports-module2.js
    │       ├── module-exports-require.js
    │       ├── module-exports-require.truth
    │       ├── module-exports-require2.js
    │       └── module-exports-require2.truth
    ├── jest/
    │   ├── graph.test.js
    │   └── linkedList.test.js
    ├── limits/
    │   ├── history.js
    │   ├── history.truth
    │   ├── overload.js
    │   └── overload.truth
    ├── process.py
    ├── required_files.py
    ├── test.py
    ├── typescript/
    │   ├── simple.truth
    │   └── simple.ts
    ├── unexpected/
    │   ├── stringiterator.js
    │   └── stringiterator.truth
    ├── unhandled/
    │   ├── classes/
    │   │   ├── class-compiled.js
    │   │   ├── class-compiled.truth
    │   │   ├── class-compiled2.js
    │   │   ├── class-compiled2.truth
    │   │   ├── class-getter.js
    │   │   └── class-getter.truth
    │   └── limits/
    │       ├── history.js
    │       ├── history.truth
    │       ├── overload.js
    │       └── overload.truth
    └── vue/
        ├── TodoList.truth
        ├── TodoList.vue
        └── example.vue

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc
================================================
{
  "env": {
    "es6": true,
    "node": true,
  },
  "rules": {
    "no-console": "off",
    "no-trailing-spaces": "error"
  },
  "parserOptions": {
    "ecmaVersion": 2017,
    "sourceType": "module"
  },
  "extends": "eslint:recommended"
}


================================================
FILE: .gitignore
================================================
node_modules
.idea
*.pickle

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class


================================================
FILE: .travis.yml
================================================
language: node_js
sudo: false
node_js:
  - "node"
before_install:
  - pyenv global 3.6
install:
  - npm install
script:
  - npm test


================================================
FILE: CONTRIBUTING.md
================================================

# How to contribute

Welcome! We are super happy that you intend to contribute to the javascript-call-graph! This is a great place to start.

#### If you find a bug

* If you can fix it, submit a PR.
* If not, open up an issue and include any information that could help others reproduce and fix.

#### If you have a feature proposal or want to contribute

* Open up an issue for discussion.
* Contribute a PR.
* Respond to code review
* Watch the PR be merged, and bathe in a job well done :icecream: :+1: :v: :palm_tree:.

## How to create a Pull Request

* First you should **fork** this repository (hit the fork button)
* **Clone** your forked repository
* **Create a branch** for you new feature
* **Commit your changes** to your branch
* **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.
* When you finished your work:
	* **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.
	* If your changes seem good for the maintainers they will accept your pull request and merge your commits into the original repository

## Keeping the fork up to date

It is an optional step. It is recommended when you are working on a larger feature or a complex bug (not a tiny quick fix).
Following the steps below ensures to track the original fork which is usually called __upstream__.
First add the original repository as a remote:

```
# Add 'upstream' repo to list of remotes
git remote add upstream https://github.com/UPSTREAM-USER/ORIGINAL-PROJECT.git
# Verify the new remote named 'upstream'
git remote -v
```

To update your fork to the latest version you have to fetch the changes from the upstream:
  
```
# Fetch from upstream remote
git fetch upstream
# View all branches, including those from upstream
git branch -va
```

Now, checkout your own master branch and merge the upstream repo's master branch:

```
# Checkout your master branch and merge upstream
git checkout master
git merge upstream/master
```

Now 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:
  
```
git checkout newfeature
# Updates origin/master
git fetch origin
# Rebases current branch onto origin/master
git rebase origin/master
```


================================================
FILE: LICENSE
================================================
Eclipse Public License - v 2.0

    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

"Contribution" means:

  a) in the case of the initial Contributor, the initial content
     Distributed under this Agreement, and

  b) in the case of each subsequent Contributor:
     i) changes to the Program, and
     ii) additions to the Program;
  where such changes and/or additions to the Program originate from
  and are Distributed by that particular Contributor. A Contribution
  "originates" from a Contributor if it was added to the Program by
  such Contributor itself or anyone acting on such Contributor's behalf.
  Contributions do not include changes or additions to the Program that
  are not Modified Works.

"Contributor" means any person or entity that Distributes the Program.

"Licensed Patents" mean patent claims licensable by a Contributor which
are necessarily infringed by the use or sale of its Contribution alone
or when combined with the Program.

"Program" means the Contributions Distributed in accordance with this
Agreement.

"Recipient" means anyone who receives the Program under this Agreement
or any Secondary License (as applicable), including Contributors.

"Derivative Works" shall mean any work, whether in Source Code or other
form, that is based on (or derived from) the Program and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship.

"Modified Works" shall mean any work in Source Code or other form that
results from an addition to, deletion from, or modification of the
contents of the Program, including, for purposes of clarity any new file
in Source Code form that contains any contents of the Program. Modified
Works shall not include works that contain only declarations,
interfaces, types, classes, structures, or files of the Program solely
in each case in order to link to, bind by name, or subclass the Program
or Modified Works thereof.

"Distribute" means the acts of a) distributing or b) making available
in any manner that enables the transfer of a copy.

"Source Code" means the form of a Program preferred for making
modifications, including but not limited to software source code,
documentation source, and configuration files.

"Secondary License" means either the GNU General Public License,
Version 2.0, or any later versions of that license, including any
exceptions or additional permissions as identified by the initial
Contributor.

2. GRANT OF RIGHTS

  a) Subject to the terms of this Agreement, each Contributor hereby
  grants Recipient a non-exclusive, worldwide, royalty-free copyright
  license to reproduce, prepare Derivative Works of, publicly display,
  publicly perform, Distribute and sublicense the Contribution of such
  Contributor, if any, and such Derivative Works.

  b) Subject to the terms of this Agreement, each Contributor hereby
  grants Recipient a non-exclusive, worldwide, royalty-free patent
  license under Licensed Patents to make, use, sell, offer to sell,
  import and otherwise transfer the Contribution of such Contributor,
  if any, in Source Code or other form. This patent license shall
  apply to the combination of the Contribution and the Program if, at
  the time the Contribution is added by the Contributor, such addition
  of the Contribution causes such combination to be covered by the
  Licensed Patents. The patent license shall not apply to any other
  combinations which include the Contribution. No hardware per se is
  licensed hereunder.

  c) Recipient understands that although each Contributor grants the
  licenses to its Contributions set forth herein, no assurances are
  provided by any Contributor that the Program does not infringe the
  patent or other intellectual property rights of any other entity.
  Each Contributor disclaims any liability to Recipient for claims
  brought by any other entity based on infringement of intellectual
  property rights or otherwise. As a condition to exercising the
  rights and licenses granted hereunder, each Recipient hereby
  assumes sole responsibility to secure any other intellectual
  property rights needed, if any. For example, if a third party
  patent license is required to allow Recipient to Distribute the
  Program, it is Recipient's responsibility to acquire that license
  before distributing the Program.

  d) Each Contributor represents that to its knowledge it has
  sufficient copyright rights in its Contribution, if any, to grant
  the copyright license set forth in this Agreement.

  e) Notwithstanding the terms of any Secondary License, no
  Contributor makes additional grants to any Recipient (other than
  those set forth in this Agreement) as a result of such Recipient's
  receipt of the Program under the terms of a Secondary License
  (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  a) the Program must also be made available as Source Code, in
  accordance with section 3.2, and the Contributor must accompany
  the Program with a statement that the Source Code for the Program
  is available under this Agreement, and informs Recipients how to
  obtain it in a reasonable manner on or through a medium customarily
  used for software exchange; and

  b) the Contributor may Distribute the Program under a license
  different than this Agreement, provided that such license:
     i) effectively disclaims on behalf of all other Contributors all
     warranties and conditions, express and implied, including
     warranties or conditions of title and non-infringement, and
     implied warranties or conditions of merchantability and fitness
     for a particular purpose;

     ii) effectively excludes on behalf of all other Contributors all
     liability for damages, including direct, indirect, special,
     incidental and consequential damages, such as lost profits;

     iii) does not attempt to limit or alter the recipients' rights
     in the Source Code under section 3.2; and

     iv) requires any subsequent distribution of the Program by any
     party to be under a license that satisfies the requirements
     of this section 3.

3.2 When the Program is Distributed as Source Code:

  a) it must be made available under this Agreement, or if the
  Program (i) is combined with other material in a separate file or
  files made available under a Secondary License, and (ii) the initial
  Contributor attached to the Source Code the notice described in
  Exhibit A of this Agreement, then the Program may be made available
  under the terms of such Secondary Licenses, and

  b) a copy of this Agreement must be included with each copy of
  the Program.

3.3 Contributors may not remove or alter any copyright, patent,
trademark, attribution notices, disclaimers of warranty, or limitations
of liability ("notices") contained within the Program from any copy of
the Program which they Distribute, provided that Contributors may add
their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities
with respect to end users, business partners and the like. While this
license is intended to facilitate the commercial use of the Program,
the Contributor who includes the Program in a commercial product
offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes
the Program in a commercial product offering, such Contributor
("Commercial Contributor") hereby agrees to defend and indemnify every
other Contributor ("Indemnified Contributor") against any losses,
damages and costs (collectively "Losses") arising from claims, lawsuits
and other legal actions brought by a third party against the Indemnified
Contributor to the extent caused by the acts or omissions of such
Commercial Contributor in connection with its distribution of the Program
in a commercial product offering. The obligations in this section do not
apply to any claims or Losses relating to any actual or alleged
intellectual property infringement. In order to qualify, an Indemnified
Contributor must: a) promptly notify the Commercial Contributor in
writing of such claim, and b) allow the Commercial Contributor to control,
and cooperate with the Commercial Contributor in, the defense and any
related settlement negotiations. The Indemnified Contributor may
participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial
product offering, Product X. That Contributor is then a Commercial
Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance
claims and warranties are such Commercial Contributor's responsibility
alone. Under this section, the Commercial Contributor would have to
defend claims against the other Contributors related to those performance
claims and warranties, and if a court requires any other Contributor to
pay any damages as a result, the Commercial Contributor must pay
those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE. Each Recipient is solely responsible for determining the
appropriateness of using and distributing the Program and assumes all
risks associated with its exercise of rights under this Agreement,
including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs
or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of
the remainder of the terms of this Agreement, and without further
action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity
(including a cross-claim or counterclaim in a lawsuit) alleging that the
Program itself (excluding combinations of the Program with other software
or hardware) infringes such Recipient's patent(s), then such Recipient's
rights granted under Section 2(b) shall terminate as of the date such
litigation is filed.

All Recipient's rights under this Agreement shall terminate if it
fails to comply with any of the material terms or conditions of this
Agreement and does not cure such failure in a reasonable period of
time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use
and distribution of the Program as soon as reasonably practicable.
However, Recipient's obligations under this Agreement and any licenses
granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement,
but in order to avoid inconsistency the Agreement is copyrighted and
may only be modified in the following manner. The Agreement Steward
reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement
Steward has the right to modify this Agreement. The Eclipse Foundation
is the initial Agreement Steward. The Eclipse Foundation may assign the
responsibility to serve as the Agreement Steward to a suitable separate
entity. Each new version of the Agreement will be given a distinguishing
version number. The Program (including Contributions) may always be
Distributed subject to the version of the Agreement under which it was
received. In addition, after a new version of the Agreement is published,
Contributor may elect to Distribute the Program (including its
Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
receives no rights or licenses to the intellectual property of any
Contributor under this Agreement, whether expressly, by implication,
estoppel or otherwise. All rights in the Program not expressly granted
under this Agreement are reserved. Nothing in this Agreement is intended
to be enforceable by any entity that is not a Contributor or Recipient.
No third-party beneficiary rights are created under this Agreement.

Exhibit A - Form of Secondary Licenses Notice

"This Source Code may also be made available under the following 
Secondary Licenses when the conditions for such availability set forth 
in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
version(s), and exceptions or additional permissions here}."

  Simply including a copy of this Agreement, including this Exhibit A
  is not sufficient to license the Source Code under Secondary Licenses.

  If it is not possible or desirable to put the notice in a particular
  file, then You may include the notice in a location (such as a LICENSE
  file in a relevant directory) where a recipient would be likely to
  look for such a notice.

  You may add additional accurate notices of copyright ownership.


================================================
FILE: README.md
================================================
# Field-based Call Graph Construction for JavaScript #


[![Build Status](https://travis-ci.org/Persper/js-callgraph.svg?branch=master)](https://travis-ci.org/Persper/js-callgraph)
[![NPM version](https://img.shields.io/badge/npm-v1.3.2-blue.svg)](https://www.npmjs.com/package/@persper/js-callgraph)
[![License](https://img.shields.io/badge/license-EPL--2.0-green.svg)](https://www.eclipse.org/legal/epl-2.0/)

This project implements a field-based call graph construction algorithm for JavaScript as described in

> A. Feldthaus, M. Schäfer, M. Sridharan, J. Dolby, F. Tip. Efficient Construction of Approximate Call Graphs for JavaScript IDE Services. In *ICSE*, 2013.

This repo builds upon [Max Schaefer](https://github.com/xiemaisi)'s original [acg.js](https://github.com/xiemaisi/acg.js) and adds

* ES6 Support
	* Arrow functions
	* Destructuring assignments
	* Classes
	* Enhanced object literals
	* Rest/Spread operator
* Module Support
	* ES6/CommonJS/AMD
* More sophisticated scoping
* Partial update to a large call graph
* Unified JSON format representing a call graph
* More flexible CLI
	* Take directory parameter
	* Support filtering files by regex
* Vue.js support (.vue files)
* More tests

## Get Started (CLI)
```
npm install -g @persper/js-callgraph
js-callgraph -h # for a list of command line arguments

# Running on simple input scripts
js-callgraph --cg input-scripts/simple-scripts/functioncall-arithmetic.js

# Running on a whole directory
js-callgraph --cg input-scripts/fullcalendar/

# Running on mixed input
js-callgraph --cg input-scripts/fullcalendar/fullcalendar/ input-scripts/fullcalendar/lib/jquery-2.1.0.js

# Saving the result into a file
js-callgraph --cg input-scripts/simple-scripts/functioncall-arithmetic.js --output filename.json

# Running on a whole directory with filtering
js-callgraph --cg input-scripts/fullcalendar/ --filter filename.filter
```

For an example of the output json, please see [here](#unified-json-format).
For an example of filtering file, please see [here](#filter-file-format).

## Programming Interface

```
const JCG = require("./src/runner");
args = { ... };
JCG.setArgs(args);                                # Optional, specify a list of arguments
JCG.setFiles(['file.js', 'directory/']);          # List of files or directories to analyze
JCG.setFilter(['-test[^\.]*.js', '+test576.js']); # Optional, please see "Filter file format" section for details
JCG.setConsoleOutput(true);                       # Optional, the console output can be turned off.
JCG.build();                                      # build returns the call graph as a JSON object, please see "Unified JSON Format" section
```

## Running Tests
To run the testing framework run:
```
npm test
```
To install the git hooks to run tests automatically pre-commit run:
```
scripts/install-hooks
```
## Structure

The 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.

All 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.

Module `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`).

Modules `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.

The remaining modules define key data structures, in several variants.

Module `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).

Modules `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.

## Unified JSON Format

```
[ # The calls are represented with a list of objects. Each call is an object in this list.
  {
    "source": { # The source object represents the start point of a call (the caller node)
      "label": "global",
      "file": "...\\input-scripts\\simple-scripts\\functioncall-arithmetic.js",
      "start": { # The start point of the source with row-column based position.
        "row": 7,
        "column": 4
      },
      "end": { # The end point of the source node with row-column based position.
        "row": 7,
        "column": 8
      },
      "range": { # The position of the source node in index-based representation.
        "start": 59,
        "end": 63
      }
    },
    "target": { # The target object represents the end point of a call (this node is called by the source)
      "label": "f",
      "file": "...\\input-scripts\\simple-scripts\\functioncall-arithmetic.js",
      "start": { # The start point of the target node with row-column based position..
        "row": 3,
        "column": 0
      },
      "end": { # The end point of the target node with row-column based position.
        "row": 5,
        "column": 1
      },
      "range": { # The position of the target node in index-based representation.
        "start": 14,
        "end": 51
      }
    }
  }
]
```

## Filter file format

Any 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.

The first character of each line represents the type of the filtering:
```
# Comment line
- Exclude
+ Include
```

An example for filtering:

```
# Filter out all source files starting with "test":
-test[^\.]*.js
# But test576.js is needed:
+test576.js
# Furthermore, files beginning with "test1742" are also needed:
+test1742[^\.]*.js
# Finally, test1742_b.js is not needed:
-test1742_b.js
```

## List of arguments

```
-h         : List of command line arguments
--fg       : print flow graph
--cg       : print call graph
--time     : print timings
--strategy : interprocedural propagation strategy; one of NONE, ONESHOT (default), DEMAND, and FULL (not yet implemented)
--countCB  : Counts the number of callbacks.
--reqJs    : Make a RequireJS dependency graph.
--output   : The output file name into which the result JSON should be saved. (extension: .json)
--filter   : Path to the filter file.
```

# Contributing

Looking to contribute something? [Here's how you can help](/CONTRIBUTING.md).

# License #

This 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`.


================================================
FILE: index.js
================================================
/*******************************************************************************
 * Copyright (c) 2018 Persper Foundation
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *******************************************************************************/
const JCG = require("./src/runner");

exports.setArgs = JCG.setArgs;
exports.setFiles = JCG.setFiles;
exports.setFilter = JCG.setFilter;
exports.setConsoleOutput = JCG.setConsoleOutput;
exports.build = JCG.build;


================================================
FILE: input-scripts/coolclock/coolclock.js
================================================
/**
 * CoolClock 2.1.4
 * Copyright 2010, Simon Baird
 * Released under the BSD License.
 *
 * Display an analog clock using canvas.
 * http://randomibis.com/coolclock/
 *
 */

// Constructor for CoolClock objects
window.CoolClock = function(options) {
	return this.init(options);
}

// Config contains some defaults, and clock skins
CoolClock.config = {
	tickDelay: 1000,
	longTickDelay: 15000,
	defaultRadius: 85,
	renderRadius: 100,
	defaultSkin: "chunkySwiss",
	// Should be in skin probably...
	// (TODO: allow skinning of digital display)
	showSecs: true,
	showAmPm: true,

	skins:	{
		// There are more skins in moreskins.js
		// Try making your own skin by copy/pasting one of these and tweaking it
		swissRail: {
			outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 },
			smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
			largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
			hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
			minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
			secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
		},
		chunkySwiss: {
			outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 },
			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
		},
		chunkySwissOnBlack: {
			outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 },
			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
		}

	},

	// Test for IE so we can nurse excanvas in a couple of places
	isIE: !!document.all,

	// Will store (a reference to) each clock here, indexed by the id of the canvas element
	clockTracker: {},

	// For giving a unique id to coolclock canvases with no id
	noIdCount: 0
};

// Define the CoolClock object's methods
CoolClock.prototype = {

	// Initialise using the parameters parsed from the colon delimited class
	init: function(options) {
		// Parse and store the options
		this.canvasId       = options.canvasId;
		this.skinId         = options.skinId || CoolClock.config.defaultSkin;
		this.displayRadius  = options.displayRadius || CoolClock.config.defaultRadius;
		this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true;
		this.gmtOffset      = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;
		this.showDigital    = typeof options.showDigital == "boolean" ? options.showDigital : false;
		this.logClock       = typeof options.logClock == "boolean" ? options.logClock : false;
		this.logClockRev    = typeof options.logClock == "boolean" ? options.logClockRev : false;

		this.tickDelay      = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ];

		// Get the canvas element
		this.canvas = document.getElementById(this.canvasId);

		// Make the canvas the requested size. It's always square.
		this.canvas.setAttribute("width",this.displayRadius*2);
		this.canvas.setAttribute("height",this.displayRadius*2);
		this.canvas.style.width = this.displayRadius*2 + "px";
		this.canvas.style.height = this.displayRadius*2 + "px";

		// Explain me please...?
		this.renderRadius = CoolClock.config.renderRadius;
		this.scale = this.displayRadius / this.renderRadius;

		// Initialise canvas context
		this.ctx = this.canvas.getContext("2d");
		this.ctx.scale(this.scale,this.scale);

		// Keep track of this object
		CoolClock.config.clockTracker[this.canvasId] = this;

		// Start the clock going
		this.tick();

		return this;
	},

	// Draw a circle at point x,y with params as defined in skin
	fullCircleAt: function(x,y,skin) {
		this.ctx.save();
		this.ctx.globalAlpha = skin.alpha;
		this.ctx.lineWidth = skin.lineWidth;

		if (!CoolClock.config.isIE) {
			this.ctx.beginPath();
		}

		if (CoolClock.config.isIE) {
			// excanvas doesn't scale line width so we will do it here
			this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
		}

		this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);

		if (CoolClock.config.isIE) {
			// excanvas doesn't close the circle so let's fill in the tiny gap
			this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);
		}

		if (skin.fillColor) {
			this.ctx.fillStyle = skin.fillColor
			this.ctx.fill();
		}
		else {
			// XXX why not stroke and fill
			this.ctx.strokeStyle = skin.color;
			this.ctx.stroke();
		}
		this.ctx.restore();
	},

	// Draw some text centered vertically and horizontally
	drawTextAt: function(theText,x,y) {
		this.ctx.save();
		this.ctx.font = '15px sans-serif';
		var tSize = this.ctx.measureText(theText);
		if (!tSize.height) tSize.height = 15; // no height in firefox.. :(
		this.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2);
		this.ctx.restore();
	},

	lpad2: function(num) {
		return (num < 10 ? '0' : '') + num;
	},

	tickAngle: function(second) {
		// Log algorithm by David Bradshaw
		var tweak = 3; // If it's lower the one second mark looks wrong (?)
		if (this.logClock) {
			return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));
		}
		else if (this.logClockRev) {
			// Flip the seconds then flip the angle (trickiness)
			second = (60 - second) % 60;
			return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));
		}
		else {
			return second/60.0;
		}
	},

	timeText: function(hour,min,sec) {
		var c = CoolClock.config;
		return '' +
			(c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +
			this.lpad2(min) +
			(c.showSecs ? ':' + this.lpad2(sec) : '') +
			(c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '')
		;
	},

	// Draw a radial line by rotating then drawing a straight line
	// Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)
	radialLineAtAngle: function(angleFraction,skin) {
		this.ctx.save();
		this.ctx.translate(this.renderRadius,this.renderRadius);
		this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));
		this.ctx.globalAlpha = skin.alpha;
		this.ctx.strokeStyle = skin.color;
		this.ctx.lineWidth = skin.lineWidth;

		if (CoolClock.config.isIE)
			// excanvas doesn't scale line width so we will do it here
			this.ctx.lineWidth = this.ctx.lineWidth * this.scale;

		if (skin.radius) {
			this.fullCircleAt(skin.startAt,0,skin)
		}
		else {
			this.ctx.beginPath();
			this.ctx.moveTo(skin.startAt,0)
			this.ctx.lineTo(skin.endAt,0);
			this.ctx.stroke();
		}
		this.ctx.restore();
	},

	render: function(hour,min,sec) {
		// Get the skin
		var skin = CoolClock.config.skins[this.skinId];
		if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];

		// Clear
		this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);

		// Draw the outer edge of the clock
		if (skin.outerBorder)
			this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);

		// Draw the tick marks. Every 5th one is a big one
		for (var i=0;i<60;i++) {
			(i%5)  && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);
			!(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);
		}

		// Write the time
		if (this.showDigital) {
			this.drawTextAt(
				this.timeText(hour,min,sec),
				this.renderRadius,
				this.renderRadius+this.renderRadius/2
			);
		}

		// Draw the hands
		if (skin.hourHand)
			this.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand);

		if (skin.minuteHand)
			this.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand);

		if (this.showSecondHand && skin.secondHand)
			this.radialLineAtAngle(this.tickAngle(sec),skin.secondHand);

		// Second hand decoration doesn't render right in IE so lets turn it off
		if (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration)
			this.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration);
	},

	// Check the time and display the clock
	refreshDisplay: function() {
		var now = new Date();
		if (this.gmtOffset != null) {
			// Use GMT + gmtOffset
			var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));
			this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds());
		}
		else {
			// Use local time
			this.render(now.getHours(),now.getMinutes(),now.getSeconds());
		}
	},

	// Set timeout to trigger a tick in the future
	nextTick: function() {
		setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay);
	},

	// Check the canvas element hasn't been removed
	stillHere: function() {
		return document.getElementById(this.canvasId) != null;
	},

	// Main tick handler. Refresh the clock then setup the next tick
	tick: function() {
		if (this.stillHere()) {
			this.refreshDisplay()
			this.nextTick();
		}
	}
};

// Find all canvas elements that have the CoolClock class and turns them into clocks
CoolClock.findAndCreateClocks = function() {
	// (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)
	var canvases = document.getElementsByTagName("canvas");
	for (var i=0;i<canvases.length;i++) {
		// Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
		var fields = canvases[i].className.split(" ")[0].split(":");
		if (fields[0] == "CoolClock") {
			if (!canvases[i].id) {
				// If there's no id on this canvas element then give it one
				canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
			}
			// Create a clock object for this element
			new CoolClock({
				canvasId:       canvases[i].id,
				skinId:         fields[1],
				displayRadius:  fields[2],
				showSecondHand: fields[3]!='noSeconds',
				gmtOffset:      fields[4],
				showDigital:    fields[5]=='showDigital',
				logClock:       fields[6]=='logClock',
				logClockRev:    fields[6]=='logClockRev'
			});
		}
	}
};

// If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
// If you do have jQuery and it's loaded already then we can do it right now
if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);


================================================
FILE: input-scripts/coolclock/excanvas.js
================================================
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
//   different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
//   width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
//   Quirks mode will draw the canvas using border-box. Either change your
//   doctype to HTML5
//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
//   or use Box Sizing Behavior from WebFX
//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Optimize. There is always room for speed improvements.

// only add this code if we do not already have a canvas implementation
if (!window.CanvasRenderingContext2D) {

(function () {

  // alias some functions to make (compiled) code shorter
  var m = Math;
  var mr = m.round;
  var ms = m.sin;
  var mc = m.cos;

  // this is used for sub pixel precision
  var Z = 10;
  var Z2 = Z / 2;

  var G_vmlCanvasManager_ = {
    init: function (opt_doc) {
      var doc = opt_doc || document;
      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
        var self = this;
        doc.attachEvent("onreadystatechange", function () {
          self.init_(doc);
        });
      }
    },

    init_: function (doc) {
      if (doc.readyState == "complete") {
        // create xmlns
        if (!doc.namespaces["g_vml_"]) {
          doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml");
        }

        // setup default css
        var ss = doc.createStyleSheet();
        ss.cssText = "canvas{display:inline-block;overflow:hidden;" +
            // default size is 300x150 in Gecko and Opera
            "text-align:left;width:300px;height:150px}" +
            "g_vml_\\:*{behavior:url(#default#VML)}";

        // find all canvas elements
        var els = doc.getElementsByTagName("canvas");
        for (var i = 0; i < els.length; i++) {
          if (!els[i].getContext) {
            this.initElement(els[i]);
          }
        }
      }
    },

    fixElement_: function (el) {
      // in IE before version 5.5 we would need to add HTML: to the tag name
      // but we do not care about IE before version 6
      var outerHTML = el.outerHTML;

      var newEl = el.ownerDocument.createElement(outerHTML);
      // if the tag is still open IE has created the children as siblings and
      // it has also created a tag with the name "/FOO"
      if (outerHTML.slice(-2) != "/>") {
        var tagName = "/" + el.tagName;
        var ns;
        // remove content
        while ((ns = el.nextSibling) && ns.tagName != tagName) {
          ns.removeNode();
        }
        // remove the incorrect closing tag
        if (ns) {
          ns.removeNode();
        }
      }
      el.parentNode.replaceChild(newEl, el);
      return newEl;
    },

    /**
     * Public initializes a canvas element so that it can be used as canvas
     * element from now on. This is called automatically before the page is
     * loaded but if you are creating elements using createElement you need to
     * make sure this is called on the element.
     * @param {HTMLElement} el The canvas element to initialize.
     * @return {HTMLElement} the element that was created.
     */
    initElement: function (el) {
      el = this.fixElement_(el);
      el.getContext = function () {
        if (this.context_) {
          return this.context_;
        }
        return this.context_ = new CanvasRenderingContext2D_(this);
      };

      // do not use inline function because that will leak memory
      el.attachEvent('onpropertychange', onPropertyChange);
      el.attachEvent('onresize', onResize);

      var attrs = el.attributes;
      if (attrs.width && attrs.width.specified) {
        // TODO: use runtimeStyle and coordsize
        // el.getContext().setWidth_(attrs.width.nodeValue);
        el.style.width = attrs.width.nodeValue + "px";
      } else {
        el.width = el.clientWidth;
      }
      if (attrs.height && attrs.height.specified) {
        // TODO: use runtimeStyle and coordsize
        // el.getContext().setHeight_(attrs.height.nodeValue);
        el.style.height = attrs.height.nodeValue + "px";
      } else {
        el.height = el.clientHeight;
      }
      //el.getContext().setCoordsize_()
      return el;
    }
  };

  function onPropertyChange(e) {
    var el = e.srcElement;

    switch (e.propertyName) {
      case 'width':
        el.style.width = el.attributes.width.nodeValue + "px";
        el.getContext().clearRect();
        break;
      case 'height':
        el.style.height = el.attributes.height.nodeValue + "px";
        el.getContext().clearRect();
        break;
    }
  }

  function onResize(e) {
    var el = e.srcElement;
    if (el.firstChild) {
      el.firstChild.style.width =  el.clientWidth + 'px';
      el.firstChild.style.height = el.clientHeight + 'px';
    }
  }

  G_vmlCanvasManager_.init();

  // precompute "00" to "FF"
  var dec2hex = [];
  for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
    }
  }

  function createMatrixIdentity() {
    return [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
  }

  function matrixMultiply(m1, m2) {
    var result = createMatrixIdentity();

    for (var x = 0; x < 3; x++) {
      for (var y = 0; y < 3; y++) {
        var sum = 0;

        for (var z = 0; z < 3; z++) {
          sum += m1[x][z] * m2[z][y];
        }

        result[x][y] = sum;
      }
    }
    return result;
  }

  function copyState(o1, o2) {
    o2.fillStyle     = o1.fillStyle;
    o2.lineCap       = o1.lineCap;
    o2.lineJoin      = o1.lineJoin;
    o2.lineWidth     = o1.lineWidth;
    o2.miterLimit    = o1.miterLimit;
    o2.shadowBlur    = o1.shadowBlur;
    o2.shadowColor   = o1.shadowColor;
    o2.shadowOffsetX = o1.shadowOffsetX;
    o2.shadowOffsetY = o1.shadowOffsetY;
    o2.strokeStyle   = o1.strokeStyle;
    o2.arcScaleX_    = o1.arcScaleX_;
    o2.arcScaleY_    = o1.arcScaleY_;
  }

  function processStyle(styleString) {
    var str, alpha = 1;

    styleString = String(styleString);
    if (styleString.substring(0, 3) == "rgb") {
      var start = styleString.indexOf("(", 3);
      var end = styleString.indexOf(")", start + 1);
      var guts = styleString.substring(start + 1, end).split(",");

      str = "#";
      for (var i = 0; i < 3; i++) {
        str += dec2hex[Number(guts[i])];
      }

      if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) {
        alpha = guts[3];
      }
    } else {
      str = styleString;
    }

    return [str, alpha];
  }

  function processLineCap(lineCap) {
    switch (lineCap) {
      case "butt":
        return "flat";
      case "round":
        return "round";
      case "square":
      default:
        return "square";
    }
  }

  /**
   * This class implements CanvasRenderingContext2D interface as described by
   * the WHATWG.
   * @param {HTMLElement} surfaceElement The element that the 2D context should
   * be associated with
   */
   function CanvasRenderingContext2D_(surfaceElement) {
    this.m_ = createMatrixIdentity();

    this.mStack_ = [];
    this.aStack_ = [];
    this.currentPath_ = [];

    // Canvas context properties
    this.strokeStyle = "#000";
    this.fillStyle = "#000";

    this.lineWidth = 1;
    this.lineJoin = "miter";
    this.lineCap = "butt";
    this.miterLimit = Z * 1;
    this.globalAlpha = 1;
    this.canvas = surfaceElement;

    var el = surfaceElement.ownerDocument.createElement('div');
    el.style.width =  surfaceElement.clientWidth + 'px';
    el.style.height = surfaceElement.clientHeight + 'px';
    el.style.overflow = 'hidden';
    el.style.position = 'absolute';
    surfaceElement.appendChild(el);

    this.element_ = el;
    this.arcScaleX_ = 1;
    this.arcScaleY_ = 1;
  };

  var contextPrototype = CanvasRenderingContext2D_.prototype;
  contextPrototype.clearRect = function() {
    this.element_.innerHTML = "";
    this.currentPath_ = [];
  };

  contextPrototype.beginPath = function() {
    // TODO: Branch current matrix so that save/restore has no effect
    //       as per safari docs.

    this.currentPath_ = [];
  };

  contextPrototype.moveTo = function(aX, aY) {
    this.currentPath_.push({type: "moveTo", x: aX, y: aY});
    this.currentX_ = aX;
    this.currentY_ = aY;
  };

  contextPrototype.lineTo = function(aX, aY) {
    this.currentPath_.push({type: "lineTo", x: aX, y: aY});
    this.currentX_ = aX;
    this.currentY_ = aY;
  };

  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                            aCP2x, aCP2y,
                                            aX, aY) {
    this.currentPath_.push({type: "bezierCurveTo",
                           cp1x: aCP1x,
                           cp1y: aCP1y,
                           cp2x: aCP2x,
                           cp2y: aCP2y,
                           x: aX,
                           y: aY});
    this.currentX_ = aX;
    this.currentY_ = aY;
  };

  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
    // the following is lifted almost directly from
    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
    var cp1x = this.currentX_ + 2.0 / 3.0 * (aCPx - this.currentX_);
    var cp1y = this.currentY_ + 2.0 / 3.0 * (aCPy - this.currentY_);
    var cp2x = cp1x + (aX - this.currentX_) / 3.0;
    var cp2y = cp1y + (aY - this.currentY_) / 3.0;
    this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, aX, aY);
  };

  contextPrototype.arc = function(aX, aY, aRadius,
                                  aStartAngle, aEndAngle, aClockwise) {
    aRadius *= Z;
    var arcType = aClockwise ? "at" : "wa";

    var xStart = aX + (mc(aStartAngle) * aRadius) - Z2;
    var yStart = aY + (ms(aStartAngle) * aRadius) - Z2;

    var xEnd = aX + (mc(aEndAngle) * aRadius) - Z2;
    var yEnd = aY + (ms(aEndAngle) * aRadius) - Z2;

    // IE won't render arches drawn counter clockwise if xStart == xEnd.
    if (xStart == xEnd && !aClockwise) {
      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                       // that can be represented in binary
    }

    this.currentPath_.push({type: arcType,
                           x: aX,
                           y: aY,
                           radius: aRadius,
                           xStart: xStart,
                           yStart: yStart,
                           xEnd: xEnd,
                           yEnd: yEnd});

  };

  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
  };

  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
    // Will destroy any existing path (same as FF behaviour)
    this.beginPath();
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.stroke();
  };

  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
    // Will destroy any existing path (same as FF behaviour)
    this.beginPath();
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.fill();
  };

  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
    var gradient = new CanvasGradient_("gradient");
    return gradient;
  };

  contextPrototype.createRadialGradient = function(aX0, aY0,
                                                   aR0, aX1,
                                                   aY1, aR1) {
    var gradient = new CanvasGradient_("gradientradial");
    gradient.radius1_ = aR0;
    gradient.radius2_ = aR1;
    gradient.focus_.x = aX0;
    gradient.focus_.y = aY0;
    return gradient;
  };

  contextPrototype.drawImage = function (image, var_args) {
    var dx, dy, dw, dh, sx, sy, sw, sh;

    // to find the original width we overide the width and height
    var oldRuntimeWidth = image.runtimeStyle.width;
    var oldRuntimeHeight = image.runtimeStyle.height;
    image.runtimeStyle.width = 'auto';
    image.runtimeStyle.height = 'auto';

    // get the original size
    var w = image.width;
    var h = image.height;

    // and remove overides
    image.runtimeStyle.width = oldRuntimeWidth;
    image.runtimeStyle.height = oldRuntimeHeight;

    if (arguments.length == 3) {
      dx = arguments[1];
      dy = arguments[2];
      sx = sy = 0;
      sw = dw = w;
      sh = dh = h;
    } else if (arguments.length == 5) {
      dx = arguments[1];
      dy = arguments[2];
      dw = arguments[3];
      dh = arguments[4];
      sx = sy = 0;
      sw = w;
      sh = h;
    } else if (arguments.length == 9) {
      sx = arguments[1];
      sy = arguments[2];
      sw = arguments[3];
      sh = arguments[4];
      dx = arguments[5];
      dy = arguments[6];
      dw = arguments[7];
      dh = arguments[8];
    } else {
      throw "Invalid number of arguments";
    }

    var d = this.getCoords_(dx, dy);

    var w2 = sw / 2;
    var h2 = sh / 2;

    var vmlStr = [];

    var W = 10;
    var H = 10;

    // For some reason that I've now forgotten, using divs didn't work
    vmlStr.push(' <g_vml_:group',
                ' coordsize="', Z * W, ',', Z * H, '"',
                ' coordorigin="0,0"' ,
                ' style="width:', W, ';height:', H, ';position:absolute;');

    // If filters are necessary (rotation exists), create them
    // filters are bog-slow, so only create them if abbsolutely necessary
    // The following check doesn't account for skews (which don't exist
    // in the canvas spec (yet) anyway.

    if (this.m_[0][0] != 1 || this.m_[0][1]) {
      var filter = [];

      // Note the 12/21 reversal
      filter.push("M11='", this.m_[0][0], "',",
                  "M12='", this.m_[1][0], "',",
                  "M21='", this.m_[0][1], "',",
                  "M22='", this.m_[1][1], "',",
                  "Dx='", mr(d.x / Z), "',",
                  "Dy='", mr(d.y / Z), "'");

      // Bounding box calculation (need to minimize displayed area so that
      // filters don't waste time on unused pixels.
      var max = d;
      var c2 = this.getCoords_(dx + dw, dy);
      var c3 = this.getCoords_(dx, dy + dh);
      var c4 = this.getCoords_(dx + dw, dy + dh);

      max.x = Math.max(max.x, c2.x, c3.x, c4.x);
      max.y = Math.max(max.y, c2.y, c3.y, c4.y);

      vmlStr.push("padding:0 ", mr(max.x / Z), "px ", mr(max.y / Z),
                  "px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
                  filter.join(""), ", sizingmethod='clip');")
    } else {
      vmlStr.push("top:", mr(d.y / Z), "px;left:", mr(d.x / Z), "px;")
    }

    vmlStr.push(' ">' ,
                '<g_vml_:image src="', image.src, '"',
                ' style="width:', Z * dw, ';',
                ' height:', Z * dh, ';"',
                ' cropleft="', sx / w, '"',
                ' croptop="', sy / h, '"',
                ' cropright="', (w - sx - sw) / w, '"',
                ' cropbottom="', (h - sy - sh) / h, '"',
                ' />',
                '</g_vml_:group>');

    this.element_.insertAdjacentHTML("BeforeEnd",
                                    vmlStr.join(""));
  };

  contextPrototype.stroke = function(aFill) {
    var lineStr = [];
    var lineOpen = false;
    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
    var color = a[0];
    var opacity = a[1] * this.globalAlpha;

    var W = 10;
    var H = 10;

    lineStr.push('<g_vml_:shape',
                 ' fillcolor="', color, '"',
                 ' filled="', Boolean(aFill), '"',
                 ' style="position:absolute;width:', W, ';height:', H, ';"',
                 ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
                 ' stroked="', !aFill, '"',
                 ' strokeweight="', this.lineWidth, '"',
                 ' strokecolor="', color, '"',
                 ' path="');

    var newSeq = false;
    var min = {x: null, y: null};
    var max = {x: null, y: null};

    for (var i = 0; i < this.currentPath_.length; i++) {
      var p = this.currentPath_[i];

      if (p.type == "moveTo") {
        lineStr.push(" m ");
        var c = this.getCoords_(p.x, p.y);
        lineStr.push(mr(c.x), ",", mr(c.y));
      } else if (p.type == "lineTo") {
        lineStr.push(" l ");
        var c = this.getCoords_(p.x, p.y);
        lineStr.push(mr(c.x), ",", mr(c.y));
      } else if (p.type == "close") {
        lineStr.push(" x ");
      } else if (p.type == "bezierCurveTo") {
        lineStr.push(" c ");
        var c = this.getCoords_(p.x, p.y);
        var c1 = this.getCoords_(p.cp1x, p.cp1y);
        var c2 = this.getCoords_(p.cp2x, p.cp2y);
        lineStr.push(mr(c1.x), ",", mr(c1.y), ",",
                     mr(c2.x), ",", mr(c2.y), ",",
                     mr(c.x), ",", mr(c.y));
      } else if (p.type == "at" || p.type == "wa") {
        lineStr.push(" ", p.type, " ");
        var c  = this.getCoords_(p.x, p.y);
        var cStart = this.getCoords_(p.xStart, p.yStart);
        var cEnd = this.getCoords_(p.xEnd, p.yEnd);

        lineStr.push(mr(c.x - this.arcScaleX_ * p.radius), ",",
                     mr(c.y - this.arcScaleY_ * p.radius), " ",
                     mr(c.x + this.arcScaleX_ * p.radius), ",",
                     mr(c.y + this.arcScaleY_ * p.radius), " ",
                     mr(cStart.x), ",", mr(cStart.y), " ",
                     mr(cEnd.x), ",", mr(cEnd.y));
      }


      // TODO: Following is broken for curves due to
      //       move to proper paths.

      // Figure out dimensions so we can do gradient fills
      // properly
      if(c) {
        if (min.x == null || c.x < min.x) {
          min.x = c.x;
        }
        if (max.x == null || c.x > max.x) {
          max.x = c.x;
        }
        if (min.y == null || c.y < min.y) {
          min.y = c.y;
        }
        if (max.y == null || c.y > max.y) {
          max.y = c.y;
        }
      }
    }
    lineStr.push(' ">');

    if (typeof this.fillStyle == "object") {
      var focus = {x: "50%", y: "50%"};
      var width = (max.x - min.x);
      var height = (max.y - min.y);
      var dimension = (width > height) ? width : height;

      focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + "%";
      focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + "%";

      var colors = [];

      // inside radius (%)
      if (this.fillStyle.type_ == "gradientradial") {
        var inside = (this.fillStyle.radius1_ / dimension * 100);

        // percentage that outside radius exceeds inside radius
        var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside;
      } else {
        var inside = 0;
        var expansion = 100;
      }

      var insidecolor = {offset: null, color: null};
      var outsidecolor = {offset: null, color: null};

      // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie
      // won't interpret it correctly
      this.fillStyle.colors_.sort(function (cs1, cs2) {
        return cs1.offset - cs2.offset;
      });

      for (var i = 0; i < this.fillStyle.colors_.length; i++) {
        var fs = this.fillStyle.colors_[i];

        colors.push( (fs.offset * expansion) + inside, "% ", fs.color, ",");

        if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
          insidecolor.offset = fs.offset;
          insidecolor.color = fs.color;
        }

        if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
          outsidecolor.offset = fs.offset;
          outsidecolor.color = fs.color;
        }
      }
      colors.pop();

      lineStr.push('<g_vml_:fill',
                   ' color="', outsidecolor.color, '"',
                   ' color2="', insidecolor.color, '"',
                   ' type="', this.fillStyle.type_, '"',
                   ' focusposition="', focus.x, ', ', focus.y, '"',
                   ' colors="', colors.join(""), '"',
                   ' opacity="', opacity, '" />');
    } else if (aFill) {
      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity, '" />');
    } else {
      lineStr.push(
        '<g_vml_:stroke',
        ' opacity="', opacity,'"',
        ' joinstyle="', this.lineJoin, '"',
        ' miterlimit="', this.miterLimit, '"',
        ' endcap="', processLineCap(this.lineCap) ,'"',
        ' weight="', this.lineWidth, 'px"',
        ' color="', color,'" />'
      );
    }

    lineStr.push("</g_vml_:shape>");

    this.element_.insertAdjacentHTML("beforeEnd", lineStr.join(""));

    this.currentPath_ = [];
  };

  contextPrototype.fill = function() {
    this.stroke(true);
  }

  contextPrototype.closePath = function() {
    this.currentPath_.push({type: "close"});
  };

  /**
   * @private
   */
  contextPrototype.getCoords_ = function(aX, aY) {
    return {
      x: Z * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - Z2,
      y: Z * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - Z2
    }
  };

  contextPrototype.save = function() {
    var o = {};
    copyState(this, o);
    this.aStack_.push(o);
    this.mStack_.push(this.m_);
    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
  };

  contextPrototype.restore = function() {
    copyState(this.aStack_.pop(), this);
    this.m_ = this.mStack_.pop();
  };

  contextPrototype.translate = function(aX, aY) {
    var m1 = [
      [1,  0,  0],
      [0,  1,  0],
      [aX, aY, 1]
    ];

    this.m_ = matrixMultiply(m1, this.m_);
  };

  contextPrototype.rotate = function(aRot) {
    var c = mc(aRot);
    var s = ms(aRot);

    var m1 = [
      [c,  s, 0],
      [-s, c, 0],
      [0,  0, 1]
    ];

    this.m_ = matrixMultiply(m1, this.m_);
  };

  contextPrototype.scale = function(aX, aY) {
    this.arcScaleX_ *= aX;
    this.arcScaleY_ *= aY;
    var m1 = [
      [aX, 0,  0],
      [0,  aY, 0],
      [0,  0,  1]
    ];

    this.m_ = matrixMultiply(m1, this.m_);
  };

  /******** STUBS ********/
  contextPrototype.clip = function() {
    // TODO: Implement
  };

  contextPrototype.arcTo = function() {
    // TODO: Implement
  };

  contextPrototype.createPattern = function() {
    return new CanvasPattern_;
  };

  // Gradient / Pattern Stubs
  function CanvasGradient_(aType) {
    this.type_ = aType;
    this.radius1_ = 0;
    this.radius2_ = 0;
    this.colors_ = [];
    this.focus_ = {x: 0, y: 0};
  }

  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
    aColor = processStyle(aColor);
    this.colors_.push({offset: 1-aOffset, color: aColor});
  };

  function CanvasPattern_() {}

  // set up externs
  G_vmlCanvasManager = G_vmlCanvasManager_;
  CanvasRenderingContext2D = CanvasRenderingContext2D_;
  CanvasGradient = CanvasGradient_;
  CanvasPattern = CanvasPattern_;

})();

} // if


================================================
FILE: input-scripts/coolclock/moreskins.js
================================================
CoolClock.config.skins = {

	swissRail: {
		outerBorder:      { lineWidth: 2, radius: 95, color: "black", alpha: 1 },
		smallIndicator:   { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
		largeIndicator:   { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
		hourHand:         { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
		secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
	},

	chunkySwiss: {
		outerBorder:      { lineWidth: 4, radius: 97, color: "black", alpha: 1 },
		smallIndicator:   { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
		largeIndicator:   { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
		hourHand:         { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
		secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
	},

	chunkySwissOnBlack: {
		outerBorder:      { lineWidth: 4, radius: 97, color: "white", alpha: 1 },
		smallIndicator:   { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
		largeIndicator:   { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
		hourHand:         { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
		minuteHand:       { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
		secondHand:       { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
		secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
	},

	fancy: {
		outerBorder:      { lineWidth: 5, radius: 95, color: "green", alpha: 0.7 },
		smallIndicator:   { lineWidth: 1, startAt: 80, endAt: 93, color: "black", alpha: 0.4 },
		largeIndicator:   { lineWidth: 1, startAt: 30, endAt: 93, color: "black", alpha: 0.5 },
		hourHand:         { lineWidth: 8, startAt: -15, endAt: 50, color: "blue", alpha: 0.7 },
		minuteHand:       { lineWidth: 7, startAt: -15, endAt: 92, color: "red", alpha: 0.7 },
		secondHand:       { lineWidth: 10, startAt: 80, endAt: 85, color: "blue", alpha: 0.3 },
		secondDecoration: { lineWidth: 1, startAt: 30, radius: 50, fillColor: "blue", color: "red", alpha: 0.15 }
	},

	machine: {
		outerBorder:      { lineWidth: 60, radius: 55, color: "#dd6655", alpha: 1 },
		smallIndicator:   { lineWidth: 4, startAt: 80, endAt: 95, color: "white", alpha: 1 },
		largeIndicator:   { lineWidth: 14, startAt: 77, endAt: 92, color: "#dd6655", alpha: 1 },
		hourHand:         { lineWidth: 18, startAt: -15, endAt: 40, color: "white", alpha: 1 },
		minuteHand:       { lineWidth: 14, startAt: 24, endAt: 100, color: "#771100", alpha: 0.5 },
		secondHand:       { lineWidth: 3, startAt: 22, endAt: 83, color: "green", alpha: 0 },
		secondDecoration: { lineWidth: 1, startAt: 52, radius: 26, fillColor: "#ffcccc", color: "red", alpha: 0.5 }
	},

	simonbaird_com: {
		hourHand:         { lineWidth: 80, startAt: -15, endAt: 35,  color: 'magenta', alpha: 0.5 },
		minuteHand:       { lineWidth: 80, startAt: -15, endAt: 65,  color: 'cyan', alpha: 0.5 },
		secondDecoration: { lineWidth: 1,  startAt: 40,  radius: 40, color: "#fff", fillColor: 'yellow', alpha: 0.5 }
	},

	// by bonstio, http://bonstio.net
	classic/*was gIG*/: {
		outerBorder:      { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
		smallIndicator:   { lineWidth: 2, startAt: 89, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator:   { lineWidth: 4, startAt: 83, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand:         { lineWidth: 5, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 4, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 2, fillColor: "black", color: "black", alpha: 1 }
	},

	modern/*was gIG2*/: {
		outerBorder:      { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
		smallIndicator:   { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator:   { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand:         { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	simple/*was gIG3*/: {
		outerBorder:      { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 },
		smallIndicator:   { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator:   { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand:         { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	// by securephp
	securephp: {
		outerBorder:      { lineWidth: 100, radius: 0.45, color: "#669900", alpha: 0.3 },
		smallIndicator:   { lineWidth: 2, startAt: 80, endAt: 90 , color: "green", alpha: 1 },
		largeIndicator:   { lineWidth: 8.5, startAt: 20, endAt: 40 , color: "green", alpha: 0.4 },
		hourHand:         { lineWidth: 3, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 2, startAt: 0, endAt: 75, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: -10, endAt: 80, color: "blue", alpha: 0.8 },
		secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
	},

	Tes2: {
		outerBorder:      { lineWidth: 4, radius: 95, color: "black", alpha: 0.5 },
		smallIndicator:   { lineWidth: 1, startAt: 10, endAt: 50 , color: "#66CCFF", alpha: 1 },
		largeIndicator:   { lineWidth: 8.5, startAt: 60, endAt: 70, color: "#6699FF", alpha: 1 },
		hourHand:         { lineWidth: 5, startAt: -15, endAt: 60, color: "black", alpha: 0.7 },
		minuteHand:       { lineWidth: 3, startAt: -25, endAt: 75, color: "black", alpha: 0.7 },
		secondHand:       { lineWidth: 1.5, startAt: -20, endAt: 88, color: "red", alpha: 1 },
		secondDecoration: { lineWidth: 1, startAt: 20, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
	},


	Lev: {
		outerBorder:      { lineWidth: 10, radius: 95, color: "#CCFF33", alpha: 0.65 },
		smallIndicator:   { lineWidth: 5, startAt: 84, endAt: 90, color: "#996600", alpha: 1 },
		largeIndicator:   { lineWidth: 40, startAt: 25, endAt: 95, color: "#336600", alpha: 0.55 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
		secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	Sand: {
		outerBorder:      { lineWidth: 1, radius: 70, color: "black", alpha: 0.5 },
		smallIndicator:   { lineWidth: 3, startAt: 50, endAt: 70, color: "#0066FF", alpha: 0.5 },
		largeIndicator:   { lineWidth: 200, startAt: 80, endAt: 95, color: "#996600", alpha: 0.75 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
		secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	Sun: {
		outerBorder:      { lineWidth: 100, radius: 140, color: "#99FFFF", alpha: 0.2 },
		smallIndicator:   { lineWidth: 300, startAt: 50, endAt: 70, color: "black", alpha: 0.1 },
		largeIndicator:   { lineWidth: 5, startAt: 80, endAt: 95, color: "black", alpha: 0.65 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 90, color: "black", alpha: 1 },
		secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	Tor: {
		outerBorder:      { lineWidth: 10, radius: 88, color: "#996600", alpha: 0.9 },
		smallIndicator:   { lineWidth: 6, startAt: -10, endAt: 73, color: "green", alpha: 0.3 },
		largeIndicator:   { lineWidth: 6, startAt: 73, endAt: 100, color: "black", alpha: 0.65 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: -73, endAt: 73, color: "black", alpha: 0.8 },
		secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	Cold: {
		outerBorder:      { lineWidth: 15, radius: 90, color: "black", alpha: 0.3 },
		smallIndicator:   { lineWidth: 15, startAt: -10, endAt: 95, color: "blue", alpha: 0.1 },
		largeIndicator:   { lineWidth: 3, startAt: 80, endAt: 95, color: "blue", alpha: 0.65 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
		secondDecoration: { lineWidth: 5, startAt: 30, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	Babosa: {
		outerBorder:      { lineWidth: 100, radius: 25, color: "blue", alpha: 0.25 },
		smallIndicator:   { lineWidth: 3, startAt: 90, endAt: 95, color: "#3366CC", alpha: 1 },
		largeIndicator:   { lineWidth: 4, startAt: 75, endAt: 95, color: "#3366CC", alpha: 1 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 85, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 12, startAt: 75, endAt: 90, color: "red", alpha: 0.8 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	Tumb: {
		outerBorder:      { lineWidth: 105, radius: 5, color: "green", alpha: 0.4 },
		smallIndicator:   { lineWidth: 1, startAt: 93, endAt: 98, color: "green", alpha: 1 },
		largeIndicator:   { lineWidth: 50, startAt: 0, endAt: 89, color: "red", alpha: 0.14 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
		secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
	},

	Stone: {
		outerBorder:      { lineWidth: 15, radius: 80, color: "#339933", alpha: 0.5 },
		smallIndicator:   { lineWidth: 2, startAt: 70, endAt: 90, color: "#FF3300", alpha: 0.7 },
		largeIndicator:   { lineWidth: 15, startAt: 0, endAt: 29, color: "#FF6600", alpha: 0.3 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
		secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
	},

	Disc: {
		outerBorder:      { lineWidth: 105, radius: 1, color: "#666600", alpha: 0.2 },
		smallIndicator:   { lineWidth: 1, startAt: 58, endAt: 95, color: "#669900", alpha: 0.8 },
		largeIndicator:   { lineWidth: 6, startAt: 25, endAt: 35, color: "#666600", alpha: 1 },
		hourHand:         { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
		minuteHand:       { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
		secondHand:       { lineWidth: 1, startAt: -75, endAt: 75, color: "#99CC00", alpha: 0.8 },
		secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "#00FF00", color: "green", alpha: 0.05 }
	},

	// By Yoo Nhe
	watermelon: {
		outerBorder:      { lineWidth: 100, radius: 1.7, color: "#d93d04", alpha: 5 },
		smallIndicator:   { lineWidth: 2, startAt: 50, endAt: 70, color: "#d93d04", alpha: 5 },
		largeIndicator:   { lineWidth: 2, startAt: 45, endAt: 94, color: "#a9bf04", alpha: 1 },
		hourHand:         { lineWidth: 5, startAt: -20, endAt: 80, color: "#8c0d17", alpha: 1 },
		minuteHand:       { lineWidth: 2, startAt: -20, endAt: 80, color: "#7c8c03", alpha: .9 },
		secondHand:       { lineWidth: 2, startAt: 70, endAt: 94, color: "#d93d04", alpha: .85 },
		secondDecoration: { lineWidth: 1, startAt: 70, radius: 3, fillColor: "red", color: "black", alpha: .7 }
	}
};


================================================
FILE: input-scripts/flotr/flotr-0.2.0-alpha.js
================================================
//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.
var 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"]};

================================================
FILE: input-scripts/flotr/flotr.debug-0.2.0-alpha.js
================================================
//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.
/* $Id: flotr.js 82 2009-01-12 19:19:31Z fabien.menager $ */

var Flotr = {
	version: '0.2.0-alpha',
	author: 'Bas Wenneker',
	website: 'http://www.solutoire.com',
	/**
	 * An object of the default registered graph types. Use Flotr.register(type, functionName)
	 * to add your own type.
	 */
	_registeredTypes:{
		'lines': 'drawSeriesLines',
		'points': 'drawSeriesPoints',
		'bars': 'drawSeriesBars',
		'candles': 'drawSeriesCandles',
		'pie': 'drawSeriesPie'
	},
	/**
	 * Can be used to register your own chart type. Default types are 'lines', 'points' and 'bars'.
	 * This is still experimental.
	 * @todo Test and confirm.
	 * @param {String} type - type of chart, like 'pies', 'bars' etc.
	 * @param {String} functionName - Name of the draw function, like 'drawSeriesPies', 'drawSeriesBars' etc.
	 */
	register: function(type, functionName){
		Flotr._registeredTypes[type] = functionName+'';	
	},
	/**
	 * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.
	 * You could also draw graphs by directly calling Flotr.Graph(element, data, options).
	 * @param {Element} el - element to insert the graph into
	 * @param {Object} data - an array or object of dataseries
	 * @param {Object} options - an object containing options
	 * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph
	 * @return {Class} returns a new graph object and of course draws the graph.
	 */
	draw: function(el, data, options, _GraphKlass_){	
		_GraphKlass_ = _GraphKlass_ || Flotr.Graph;
		return new _GraphKlass_(el, data, options);
	},
	/**
	 * Collects dataseries from input and parses the series into the right format. It returns an Array 
	 * of Objects each having at least the 'data' key set.
	 * @param {Array/Object} data - Object or array of dataseries
	 * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)})
	 */
	getSeries: function(data){
		return data.collect(function(serie){
			var i, serie = (serie.data) ? Object.clone(serie) : {'data': serie};
			for (i = serie.data.length-1; i > -1; --i) {
				serie.data[i][1] = (serie.data[i][1] === null ? null : parseFloat(serie.data[i][1])); 
			}
			return serie;
		});
	},
	/**
	 * Recursively merges two objects.
	 * @param {Object} src - source object (likely the object with the least properties)
	 * @param {Object} dest - destination object (optional, object with the most properties)
	 * @return {Object} recursively merged Object
	 */
	merge: function(src, dest){
		var result = dest || {};
		for(var i in src){
			result[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];		
		}
		return result;
	},	
	/**
	 * Function calculates the ticksize and returns it.
	 * @param {Integer} noTicks - number of ticks
	 * @param {Integer} min - lower bound integer value for the current axis
	 * @param {Integer} max - upper bound integer value for the current axis
	 * @param {Integer} decimals - number of decimals for the ticks
	 * @return {Integer} returns the ticksize in pixels
	 */
	getTickSize: function(noTicks, min, max, decimals){
		var delta = (max - min) / noTicks;	
		var magn = Flotr.getMagnitude(delta);
		
		// Norm is between 1.0 and 10.0.
		var norm = delta / magn;
		
		var tickSize = 10;
		if(norm < 1.5) tickSize = 1;
		else if(norm < 2.25) tickSize = 2;
		else if(norm < 3) tickSize = ((decimals == 0) ? 2 : 2.5);
		else if(norm < 7.5) tickSize = 5;
		
		return tickSize * magn;
	},
	/**
	 * Default tick formatter.
	 * @param {String/Integer} val - tick value integer
	 * @return {String} formatted tick string
	 */
	defaultTickFormatter: function(val){
		return val+'';
	},
	/**
	 * Formats the mouse tracker values.
	 * @param {Object} obj - Track value Object {x:..,y:..}
	 * @return {String} Formatted track string
	 */
	defaultTrackFormatter: function(obj){
		return '('+obj.x+', '+obj.y+')';
	}, 
	defaultPieLabelFormatter: function(slice) {
	  return (slice.fraction*100).toFixed(2)+'%';
	},
	/**
	 * Returns the magnitude of the input value.
	 * @param {Integer/Float} x - integer or float value
	 * @return {Integer/Float} returns the magnitude of the input value
	 */
	getMagnitude: function(x){
		return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
	},
	toPixel: function(val){
		return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);
	},
	toRad: function(angle){
		return -angle * (Math.PI/180);
	},
	/**
	 * Parses a color string and returns a corresponding Color.
	 * @param {String} str - string thats representing a color
	 * @return {Color} returns a Color object or false
	 */
	parseColor: function(str){
		if (str instanceof Flotr.Color) return str;
		
		var result, Color = Flotr.Color;

		// rgb(num,num,num)
		if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)))
			return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));
	
		// rgba(num,num,num,num)
		if((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)))
			return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));
			
		// rgb(num%,num%,num%)
		if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)))
			return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);
	
		// rgba(num%,num%,num%,num)
		if((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)))
			return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));
			
		// #a0b1c2
		if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))
			return new Color(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16));
	
		// #fff
		if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))
			return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));

		// Otherwise, we're most likely dealing with a named color.
		var name = str.strip().toLowerCase();
		if(name == 'transparent'){
			return new Color(255, 255, 255, 0);
		}
		return ((result = Color.lookupColors[name])) ? new Color(result[0], result[1], result[2]) : false;
	},
	/**
	 * Extracts the background-color of the passed element.
	 * @param {Element} element
	 * @return {String} color string
	 */
	extractColor: function(element){
		var color;
		// Loop until we find an element with a background color and stop when we hit the body element. 
		do {
			color = element.getStyle('background-color').toLowerCase();
			if(!(color == '' || color == 'transparent')) break;
			element = element.up(0);
		} while(!element.nodeName.match(/^body$/i));

		// Catch Safari's way of signaling transparent.
		return (color == 'rgba(0, 0, 0, 0)') ? 'transparent' : color;
	}
};
/**
 * Flotr Graph class that plots a graph on creation.

 */
Flotr.Graph = Class.create({
	/**
	 * Flotr Graph constructor.
	 * @param {Element} el - element to insert the graph into
	 * @param {Object} data - an array or object of dataseries
 	 * @param {Object} options - an object containing options
	 */
	initialize: function(el, data, options){
		this.el = $(el);
		
		if (!this.el) throw 'The target container doesn\'t exist';
		
		this.data = data;
		this.series = Flotr.getSeries(data);
		this.setOptions(options);
		
		// Initialize some variables
		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;
    
		// Create and prepare canvas.
		this.constructCanvas();
		
		// Add event handlers for mouse tracking, clicking and selection
		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();
    
    // Graph and Data tabs
    if (this.options.spreadsheet.show) 
      this.constructTabs();
	},
	/**
	 * Sets options and initializes some variables and color specific values, used by the constructor. 
	 * @param {Object} opts - options object
	 */
  setOptions: function(opts){
    var options = {
      colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.
      title: null,
      subtitle: null,
      legend: {
        show: true,            // => setting to true will show the legend, hide otherwise
        noColumns: 1,          // => number of colums in legend table // @todo: doesn't work for HtmlText = false
        labelFormatter: Prototype.K, // => fn: string -> string
        labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes
        labelBoxWidth: 14,
        labelBoxHeight: 10,
        labelBoxMargin: 5,
        container: null,       // => container (as jQuery object) to put legend in, null means default on top of graph
        position: 'nw',        // => position of default legend container within plot
        margin: 5,             // => distance from grid edge to default legend container within plot
        backgroundColor: null, // => null means auto-detect
        backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background
      },
      xaxis: {
        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
        labelsAngle: 0,        // => Labels' angle, in degrees
        title: null,           // => axis title
        titleAngle: 0,         // => axis title's angle, in degrees
        noTicks: 5,            // => number of ticks for automagically generated ticks
        tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string
        tickDecimals: null,    // => no. of decimals, null means auto
        min: null,             // => min. value to show, null means set automatically
        max: null,             // => max. value to show, null means set automatically
        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
        color: null
      },
      x2axis: {},
      yaxis: {
        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
        labelsAngle: 0,        // => Labels' angle, in degrees
        title: null,           // => axis title
        titleAngle: 90,        // => axis title's angle, in degrees
        noTicks: 5,            // => number of ticks for automagically generated ticks
        tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string
        tickDecimals: null,    // => no. of decimals, null means auto
        min: null,             // => min. value to show, null means set automatically
        max: null,             // => max. value to show, null means set automatically
        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
        color: null
      },
      y2axis: {
      	titleAngle: 270
      },
      points: {
        show: false,           // => setting to true will show points, false will hide
        radius: 3,             // => point radius (pixels)
        lineWidth: 2,          // => line width in pixels
        fill: true,            // => true to fill the points with a color, false for (transparent) no fill
        fillColor: '#FFFFFF',  // => fill color
        fillOpacity: 0.4
      },
      lines: {
        show: false,           // => setting to true will show lines, false will hide
        lineWidth: 2,          // => line width in pixels
        fill: false,           // => true to fill the area from the line to the x axis, false for (transparent) no fill
        fillColor: null,       // => fill color
        fillOpacity: 0.4       // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
      },
      bars: {
        show: false,           // => setting to true will show bars, false will hide
        lineWidth: 2,          // => in pixels
        barWidth: 1,           // => in units of the x axis
        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill
        fillColor: null,       // => fill color
        fillOpacity: 0.4,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
        horizontal: false,
        stacked: false
      },
      candles: {
        show: false,           // => setting to true will show candle sticks, false will hide
        lineWidth: 1,          // => in pixels
        wickLineWidth: 1,      // => in pixels
        candleWidth: 0.6,      // => in units of the x axis
        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill
        upFillColor: '#00A8F0',// => up sticks fill color
        downFillColor: '#CB4B4B',// => down sticks fill color
        fillOpacity: 0.5,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
        barcharts: false       // => draw as barcharts (not standard bars but financial barcharts)
      },
      pie: {
        show: false,           // => setting to true will show bars, false will hide
        lineWidth: 1,          // => in pixels
        fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill
        fillColor: null,       // => fill color
        fillOpacity: 0.6,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
        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',      // => primary color used for outline and labels
        backgroundColor: null, // => null for transparent, else color
        tickColor: '#DDDDDD',  // => color used for the ticks
        labelMargin: 3,        // => margin in pixels
        verticalLines: true,   // => whether to show gridlines in vertical direction
        horizontalLines: true, // => whether to show gridlines in horizontal direction
        outlineWidth: 2        // => width of the grid outline/border in pixels
      },
      selection: {
        mode: null,            // => one of null, 'x', 'y' or 'xy'
        color: '#B6D9FF',      // => selection box color
        fps: 20                // => frames-per-second
      },
      mouse: {
        track: false,          // => true to track the mouse, no tracking otherwise
        position: 'se',        // => position of the value box (default south-east)
        relative: false,       // => next to the mouse cursor
        trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box
        margin: 5,             // => margin in pixels of the valuebox
        lineColor: '#FF3F19',  // => line color of points that are drawn when mouse comes near a value of a series
        trackDecimals: 1,      // => decimals for the track values
        sensibility: 2,        // => the lower this number, the more precise you have to aim to show a value
        radius: 3              // => radius of the track point
      },
      shadowSize: 4,           // => size of the 'fake' shadow
      defaultType: 'lines',    // => default series type
      HtmlText: true,          // => wether to draw the text using HTML or on the canvas
      fontSize: 7.5,             // => canvas' text font size
      spreadsheet: {
      	show: false,           // => show the data grid using two tabs
      	tabGraphLabel: 'Graph',
      	tabDataLabel: 'Data',
      	toolbarDownload: 'Download CSV', // @todo: add language support
      	toolbarSelectAll: 'Select all'
      }
    }
    
    options.x2axis = Object.extend(Object.clone(options.xaxis), options.x2axis);
    options.y2axis = Object.extend(Object.clone(options.yaxis), options.y2axis);
    this.options = Flotr.merge((opts || {}), options);
    
    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}
    };
		
		// Initialize some variables used throughout this function.
		var assignedColors = [],
		    colors = [],
		    ln = this.series.length,
		    neededColors = this.series.length,
		    oc = this.options.colors, 
		    usedColors = [],
		    variation = 0,
		    c, i, j, s, tooClose;

		// Collect user-defined colors from series.
		for(i = neededColors - 1; i > -1; --i){
			c = this.series[i].color;
			if(c != null){
				--neededColors;
				if(Object.isNumber(c)) assignedColors.push(c);
				else usedColors.push(Flotr.parseColor(c));
			}
		}
		
		// Calculate the number of colors that need to be generated.
		for(i = assignedColors.length - 1; i > -1; --i)
			neededColors = Math.max(neededColors, assignedColors[i] + 1);

		// Generate needed number of colors.
		for(i = 0; colors.length < neededColors;){
			c = (oc.length == i) ? new Flotr.Color(100, 100, 100) : Flotr.parseColor(oc[i]);
			
			// Make sure each serie gets a different color.
			var sign = variation % 2 == 1 ? -1 : 1;
			var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
			c.scale(factor, factor, factor);

			/**
			 * @todo if we're getting too close to something else, we should probably skip this one
			 */
			colors.push(c);
			
			if(++i >= oc.length){
				i = 0;
				++variation;
			}
		}
	
		// Fill the options with the generated colors.
		for(i = 0, j = 0; i < ln; ++i){
			s = this.series[i];

			// Assign the color.
			if(s.color == null){
				s.color = colors[j++].toString();
			}else if(Object.isNumber(s.color)){
				s.color = colors[s.color].toString();
			}
			
      if (!s.xaxis) s.xaxis = this.axes.x;
           if (s.xaxis == 1) s.xaxis = this.axes.x;
      else if (s.xaxis == 2) s.xaxis = this.axes.x2;
  
      if (!s.yaxis) s.yaxis = this.axes.y;
           if (s.yaxis == 1) s.yaxis = this.axes.y;
      else if (s.yaxis == 2) s.yaxis = this.axes.y2;
			
			// Apply missing options to the series.
			s.lines   = Object.extend(Object.clone(this.options.lines), s.lines);
			s.points  = Object.extend(Object.clone(this.options.points), s.points);
			s.bars    = Object.extend(Object.clone(this.options.bars), s.bars);
			s.candles = Object.extend(Object.clone(this.options.candles), s.candles);
			s.pie     = Object.extend(Object.clone(this.options.pie), s.pie);
			s.mouse   = Object.extend(Object.clone(this.options.mouse), s.mouse);
			
			if(s.shadowSize == null) s.shadowSize = this.options.shadowSize;
		}
	},
	/**
	 * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use 
	 * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements
	 * are created, the elements are inserted into the container element.
	 */
	constructCanvas: function(){
		var el = this.el,
			size, c, oc;
		
  	this.canvas = el.select('.flotr-canvas')[0];
		this.overlay = el.select('.flotr-overlay')[0];
		
		el.childElements().invoke('remove');

		// For positioning labels and overlay.
		el.setStyle({position:'relative', cursor:'default'});

		this.canvasWidth = el.getWidth();
		this.canvasHeight = el.getHeight();
		size = {'width': this.canvasWidth, 'height': this.canvasHeight};

		if(this.canvasWidth <= 0 || this.canvasHeight <= 0){
			throw 'Invalid dimensions for plot, width = ' + this.canvasWidth + ', height = ' + this.canvasHeight;
		}

		// Insert main canvas.
		if (!this.canvas) {
			c = this.canvas = new Element('canvas', size);
			c.className = 'flotr-canvas';
			c = c.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
		} else {
			c = this.canvas.writeAttribute(size);
		}
		el.insert(c);
		
		if(Prototype.Browser.IE){
			c = window.G_vmlCanvasManager.initElement(c);
		}
		this.ctx = c.getContext('2d');
    
		// Insert overlay canvas for interactive features.
		if (!this.overlay) {
			oc = this.overlay = new Element('canvas', size);
			oc.className = 'flotr-overlay';
			oc = oc.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
		} else {
			oc = this.overlay.writeAttribute(size);
		}
		el.insert(oc);
		
		if(Prototype.Browser.IE){
			oc = window.G_vmlCanvasManager.initElement(oc);
		}
		this.octx = oc.getContext('2d');

		// Enable text functions
		if (window.CanvasText) {
		  CanvasText.enable(this.ctx);
		  CanvasText.enable(this.octx);
		  this.textEnabled = true;
		}
	},
  getTextDimensions: function(text, canvasStyle, HtmlStyle, className) {
    if (!text) return {width:0, height:0};
    
    if (!this.options.HtmlText && this.textEnabled) {
      var bounds = this.ctx.getTextBounds(text, canvasStyle);
      return {
        width: bounds.width+2, 
        height: bounds.height+6
      };
    }
    else {
      var dummyDiv = this.el.insert('<div style="position:absolute;top:-10000px;'+HtmlStyle+'" class="'+className+' flotr-dummy-div">' + text + '</div>').select(".flotr-dummy-div")[0];
      dim = dummyDiv.getDimensions();
      dummyDiv.remove();
      return dim;
    }
  },
	loadDataGrid: function(){
    if (this.seriesData) return this.seriesData;

		var s = this.series;
		var dg = [];

    /* The data grid is a 2 dimensions array. There is a row for each X value.
     * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one)
    **/
		for(i = 0; i < s.length; ++i){
			s[i].data.each(function(v) {
				var x = v[0],
				    y = v[1];
				if (r = dg.find(function(row) {return row[0] == x})) {
					r[i+1] = y;
				}
				else {
					var newRow = [];
					newRow[0] = x;
					newRow[i+1] = y
					dg.push(newRow);
				}
			});
		}
		
    // The data grid is sorted by x value
		dg = dg.sortBy(function(v) {
			return v[0];
		});
		return this.seriesData = dg;
	},
	
	// @todo: make a tab manager (Flotr.Tabs)
  showTab: function(tabName, onComplete){
    var elementsClassNames = 'canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle';
    switch(tabName) {
      case 'graph':
        this.datagrid.up().hide();
        this.el.select(elementsClassNames).invoke('show');
        this.tabs.data.removeClassName('selected');
        this.tabs.graph.addClassName('selected');
      break;
      case 'data':
        this.constructDataGrid();
        this.datagrid.up().show();
        this.el.select(elementsClassNames).invoke('hide');
        this.tabs.data.addClassName('selected');
        this.tabs.graph.removeClassName('selected');
      break;
    }
  },
  constructTabs: function(){
    var tabsContainer = new Element('div', {className:'flotr-tabs-group', style:'position:absolute;left:0px;top:'+this.canvasHeight+'px;width:'+this.canvasWidth+'px;'});
    this.el.insert({bottom: tabsContainer});
    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)
    }
    
    tabsContainer.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));
  },
  
  // @todo: make a spreadsheet manager (Flotr.Spreadsheet)
	constructDataGrid: function(){
    // If the data grid has already been built, nothing to do here
    if (this.datagrid) return this.datagrid;
    
		var i, j, 
        s = this.series,
        datagrid = this.loadDataGrid();

		var t = this.datagrid = new Element('table', {className:'flotr-datagrid', style:'height:100px;'});
		var colgroup = ['<colgroup><col />'];
		
		// First row : series' labels
		var html = ['<tr class="first-row">'];
		html.push('<th>&nbsp;</th>');
		for (i = 0; i < s.length; ++i) {
			html.push('<th scope="col">'+(s[i].label || String.fromCharCode(65+i))+'</th>');
			colgroup.push('<col />');
		}
		html.push('</tr>');
		
		// Data rows
		for (j = 0; j < datagrid.length; ++j) {
			html.push('<tr>');
			for (i = 0; i < s.length+1; ++i) {
        var tag = 'td';
        var content = (datagrid[j][i] != null ? Math.round(datagrid[j][i]*100000)/100000 : '');
        
        if (i == 0) {
          tag = 'th';
          var label;
          if(this.options.xaxis.ticks) {
            var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == datagrid[j][i] });
            if (tick) label = tick[1];
          } 
          else {
            label = this.options.xaxis.tickFormatter(content);
          }
          
          if (label) content = label;
        }

				html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+'</'+tag+'>');
			}
			html.push('</tr>');
		}
		colgroup.push('</colgroup>');
    t.update(colgroup.join('')+html.join(''));
    
    if (!Prototype.Browser.IE) {
      t.select('td').each(function(td) {
      	td.observe('mouseover', function(e){
      		td = e.element();
      		var siblings = td.previousSiblings();
      		
      		t.select('th[scope=col]')[siblings.length-1].addClassName('hover');
      		t.select('colgroup col')[siblings.length].addClassName('hover');
      	});
      	
      	td.observe('mouseout', function(){
      		t.select('colgroup col.hover, th.hover').each(function(e){e.removeClassName('hover')});
      	});
      });
    }
    
		var toolbar = 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 container = new Element('div', {className:'flotr-datagrid-container', style:'left:0px;top:0px;width:'+this.canvasWidth+'px;height:'+this.canvasHeight+'px;overflow:auto;'});
		container.insert(toolbar);
		t.wrap(container.hide());
		
		this.el.insert(container);
    return t;
  },
  selectAllData: function(){
    if (this.tabs) {
      var selection, range, doc, win, node = this.constructDataGrid();
  
      this.showTab('data');
      
      // deferred to be able to select the table
      (function () {
        if ((doc = node.ownerDocument) && (win = doc.defaultView) && 
          win.getSelection && doc.createRange && 
          (selection = window.getSelection()) && 
          selection.removeAllRanges) {
           range = doc.createRange();
           range.selectNode(node);
           selection.removeAllRanges();
           selection.addRange(range);
        }
        else if (document.body && document.body.createTextRange && 
          (range = document.body.createTextRange())) {
           range.moveToElementText(node);
           range.select();
        }
      }).defer();
      return true;
    }
    else return false;
  },
  downloadCSV: function(){
    var i, csv = '"x"',
        series = this.series,
        dg = this.loadDataGrid();
    
    for (i = 0; i < series.length; ++i) {
      csv += '%09"'+(series[i].label || String.fromCharCode(65+i))+'"'; // \t
    }
    csv += "%0D%0A"; // \r\n
    
    for (i = 0; i < dg.length; ++i) {
      if (this.options.xaxis.ticks) {
        var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == dg[i][0] });
        if (tick) dg[i][0] = tick[1];
      } else {
        dg[i][0] = this.options.xaxis.tickFormatter(dg[i][0]);
      }
      csv += dg[i].join('%09')+"%0D%0A"; // \t and \r\n
    }
    if (Prototype.Browser.IE) {
      csv = csv.gsub('%09', '\t').gsub('%0A', '\n').gsub('%0D', '\r');
      window.open().document.write(csv);
    }
    else {
      window.open('data:text/csv,'+csv);
    }
  },
	/**
	 * Initializes event some handlers.
	 */
	initEvents: function () {
  	//@todo: maybe stopObserving with only flotr functions
  	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));
	},
	/**
	 * Function determines the min and max values for the xaxis and yaxis.
	 */
	findDataRanges: function(){
		var s = this.series, 
		    a = this.axes;
		
		a.x.datamin = 0;  a.x.datamax  = 0;
		a.x2.datamin = 0; a.x2.datamax = 0;
		a.y.datamin = 0;  a.y.datamax  = 0;
		a.y2.datamin = 0; a.y2.datamax = 0;
		
		if(s.length > 0){
			var i, j, h, x, y, data, xaxis, yaxis;
		
			// Get datamin, datamax start values 
			for(i = 0; i < s.length; ++i) {
				data = s[i].data, 
				xaxis = s[i].xaxis, 
				yaxis = s[i].yaxis;
				
				if (data.length > 0 && !s[i].hide) {
					if (!xaxis.used) xaxis.datamin = xaxis.datamax = data[0][0];
					if (!yaxis.used) yaxis.datamin = yaxis.datamax = data[0][1];
					xaxis.used = true;
					yaxis.used = true;

					for(h = data.length - 1; h > -1; --h){
  					x = data[h][0];
  			         if(x < xaxis.datamin) xaxis.datamin = x;
   					else if(x > xaxis.datamax) xaxis.datamax = x;
  			    
  					for(j = 1; j < data[h].length; j++){
  						y = data[h][j];
  				         if(y < yaxis.datamin) yaxis.datamin = y;
  	  				else if(y > yaxis.datamax) yaxis.datamax = y;
  					}
					}
				}
			}
		}
		
		this.findXAxesValues();
		
		this.calculateRange(a.x);
		this.extendXRangeIfNeededByBar(a.x);
		
		if (a.x2.used) {
			this.calculateRange(a.x2);
		  this.extendXRangeIfNeededByBar(a.x2);
		}
		
		this.calculateRange(a.y);
		this.extendYRangeIfNeededByBar(a.y);
		
		if (a.y2.used) {
  		this.calculateRange(a.y2);
  		this.extendYRangeIfNeededByBar(a.y2);
		}
	},
	/**
	 * Calculates the range of an axis to apply autoscaling.
	 */
	calculateRange: function(axis){
		var o = axis.options,
		  min = o.min != null ? o.min : axis.datamin,
			max = o.max != null ? o.max : axis.datamax,
			margin;

		if(max - min == 0.0){
			var widen = (max == 0.0) ? 1.0 : 0.01;
			min -= widen;
			max += widen;
		}
		axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);

		// Autoscaling.
		if(o.min == null){
			// Add a margin.
			margin = o.autoscaleMargin;
			if(margin != 0){
				min -= axis.tickSize * margin;
				
				// Make sure we don't go below zero if all values are positive.
				if(min < 0 && axis.datamin >= 0) min = 0;
				min = axis.tickSize * Math.floor(min / axis.tickSize);
			}
		}
		if(o.max == null){
			margin = o.autoscaleMargin;
			if(margin != 0){
				max += axis.tickSize * margin;
				if(max > 0 && axis.datamax <= 0) max = 0;				
				max = axis.tickSize * Math.ceil(max / axis.tickSize);
			}
		}
		axis.min = min;
		axis.max = max;
	},
	/**
	 * Bar series autoscaling in x direction.
	 */
	extendXRangeIfNeededByBar: function(axis){
		if(axis.options.max == null){
			var newmax = axis.max,
			    i, s, b, c,
			    stackedSums = [], 
			    lastSerie = null;

			for(i = 0; i < this.series.length; ++i){
				s = this.series[i];
				b = s.bars;
				c = s.candles;
				if(s.axis == axis && (b.show || c.show)) {
					if (!b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){
						newmax = axis.max + s.bars.barWidth;
					}
					if(b.stacked && b.horizontal){
						for (j = 0; j < s.data.length; j++) {
							if (s.bars.show && s.bars.stacked) {
								var x = s.data[j][0];
								stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
								lastSerie = s;
							}
						}
				    
						for (j = 0; j < stackedSums.length; j++) {
				    	newmax = Math.max(stackedSums[j], newmax);
						}
					}
				}
			}
			axis.lastSerie = lastSerie;
			axis.max = newmax;
		}
	},
	/**
	 * Bar series autoscaling in y direction.
	 */
	extendYRangeIfNeededByBar: function(axis){
		if(axis.options.max == null){
			var newmax = axis.max,
				  i, s, b, c,
				  stackedSums = [],
				  lastSerie = null;
									
			for(i = 0; i < this.series.length; ++i){
				s = this.series[i];
				b = s.bars;
				c = s.candles;
				if (s.yaxis == axis && b.show && !s.hide) {
					if (b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){
						newmax = axis.max + b.barWidth;
					}
					if(b.stacked && !b.horizontal){
						for (j = 0; j < s.data.length; j++) {
							if (s.bars.show && s.bars.stacked) {
								var x = s.data[j][0];
								stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
								lastSerie = s;
							}
						}
						
						for (j = 0; j < stackedSums.length; j++) {
							newmax = Math.max(stackedSums[j], newmax);
						}
					}
				}
			}
			axis.lastSerie = lastSerie;
			axis.max = newmax;
		}
	},
	/** 
	 * Find every values of the x axes
	 */
	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]] = {};
			}
		}
	},
	/**
	 * Calculate axis ticks.
	 * @param {Object} axis - axis object
	 * @param {Object} o - axis options
	 */
	calculateTicks: function(axis){
		var o = axis.options, i, v;
		
		axis.ticks = [];	
		if(o.ticks){
			var ticks = o.ticks, t, label;

			if(Object.isFunction(ticks)){
				ticks = ticks({min: axis.min, max: axis.max});
			}
			
			// Clean up the user-supplied ticks, copy them over.
			for(i = 0; i < ticks.length; ++i){
				t = ticks[i];
				if(typeof(t) == 'object'){
					v = t[0];
					label = (t.length > 1) ? t[1] : o.tickFormatter(v);
				}else{
					v = t;
					label = o.tickFormatter(v);
				}
				axis.ticks[i] = { v: v, label: label };
			}
		}
    else {
			// Round to nearest multiple of tick size.
			var start = axis.tickSize * Math.ceil(axis.min / axis.tickSize),
				  decimals;
			
			// Then store all possible ticks.
			for(i = 0; start + i * axis.tickSize <= axis.max; ++i){
				v = start + i * axis.tickSize;
				
				// Round (this is always needed to fix numerical instability).
				decimals = o.tickDecimals;
				if(decimals == null) decimals = 1 - Math.floor(Math.log(axis.tickSize) / Math.LN10);
				if(decimals < 0) decimals = 0;
				
				v = v.toFixed(decimals);
				axis.ticks.push({ v: v, label: o.tickFormatter(v) });
			}
		}
	},
	/**
	 * Calculates axis label sizes.
	 */
	calculateSpacing: function(){
		var a = this.axes,
  			options = this.options,
  			series = this.series,
  			margin = options.grid.labelMargin,
  			x = a.x,
  			x2 = a.x2,
  			y = a.y,
  			y2 = a.y2,
  			maxOutset = 2,
  			i, j, l, dim;
		
		// Labels width and height
		[x, x2, y, y2].each(function(axis) {
			var maxLabel = '';
			
		  if (axis.options.showLabels) {
				for(i = 0; i < axis.ticks.length; ++i){
					l = axis.ticks[i].label.length;
					if(l > maxLabel.length){
						maxLabel = axis.ticks[i].label;
					}
				}
	    }
		  axis.maxLabel  = this.getTextDimensions(maxLabel, {size:options.fontSize, angle: Flotr.toRad(axis.options.labelsAngle)}, 'font-size:smaller;', 'flotr-grid-label');
		  axis.titleSize = this.getTextDimensions(axis.options.title, {size: options.fontSize*1.2, angle: Flotr.toRad(axis.options.titleAngle)}, 'font-weight:bold;', 'flotr-axis-title');
		}, this);

    // Title height
    dim = this.getTextDimensions(options.title, {size: options.fontSize*1.5}, 'font-size:1em;font-weight:bold;', 'flotr-title');
    this.titleHeight = dim.height;
    
    // Subtitle height
    dim = this.getTextDimensions(options.subtitle, {size: options.fontSize}, 'font-size:smaller;', 'flotr-subtitle');
    this.subtitleHeight = dim.height;

		// Grid outline line width.
		if(options.show){
			maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2);
		}
		for(j = 0; j < options.length; ++j){
			if (series[j].points.show){
				maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);
			}
		}
		
		var p = this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};
		p.left = p.right = p.top = p.bottom = maxOutset;
		
		p.bottom += (x.options.showLabels ?  (x.maxLabel.height  + margin) : 0) + 
		            (x.options.title ?       (x.titleSize.height + margin) : 0);
		
    p.top    += (x2.options.showLabels ? (x2.maxLabel.height  + margin) : 0) + 
                (x2.options.title ?      (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight;
    
		p.left   += (y.options.showLabels ?  (y.maxLabel.width  + margin) : 0) + 
                (y.options.title ?       (y.titleSize.width + margin) : 0);
		
		p.right  += (y2.options.showLabels ? (y2.maxLabel.width  + margin) : 0) + 
                (y2.options.title ?      (y2.titleSize.width + margin) : 0);
    
    p.top = Math.floor(p.top); // In order the outline not to be blured
    
		this.plotWidth  = this.canvasWidth - p.left - p.right;
		this.plotHeight = this.canvasHeight - p.bottom - p.top;
		
		x.scale  = this.plotWidth / (x.max - x.min);
		x2.scale = this.plotWidth / (x2.max - x2.min);
		y.scale  = this.plotHeight / (y.max - y.min);
		y2.scale = this.plotHeight / (y2.max - y2.min);
	},
	/**
	 * Draws grid, labels and series.
	 */
	draw: function() {
		this.drawGrid();
		this.drawLabels();
    this.drawTitles();
    
		if(this.series.length){
			this.el.fire('flotr:beforedraw', [this.series, this]);
			for(var i = 0; i < this.series.length; i++){
				if (!this.series[i].hide)
					this.drawSeries(this.series[i]);
			}
		}
		this.el.fire('flotr:afterdraw', [this.series, this]);
	},
	/**
	 * Translates absolute horizontal x coordinates to relative coordinates.
	 * @param {Integer} x - absolute integer x coordinate
	 * @return {Integer} translated relative x coordinate
	 */
	tHoz: function(x, axis){
		axis = axis || this.axes.x;
		return (x - axis.min) * axis.scale;
	},
	/**
	 * Translates absolute vertical x coordinates to relative coordinates.
	 * @param {Integer} y - absolute integer y coordinate
	 * @return {Integer} translated relative y coordinate
	 */
	tVert: function(y, axis){
		axis = axis || this.axes.y;
		return this.plotHeight - (y - axis.min) * axis.scale;
	},
	/**
	 * Draws a grid for the graph.
	 */
	drawGrid: function(){
		var v, o = this.options,
		    ctx = this.ctx;
		if(o.grid.verticalLines || o.grid.horizontalLines){
			this.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);
		}
		ctx.save();
		ctx.translate(this.plotOffset.left, this.plotOffset.top);

		// Draw grid background, if present in options.
		if(o.grid.backgroundColor != null){
			ctx.fillStyle = o.grid.backgroundColor;
			ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);
		}
		
		// Draw grid lines in vertical direction.
		ctx.lineWidth = 1;
		ctx.strokeStyle = o.grid.tickColor;
		ctx.beginPath();
		if(o.grid.verticalLines){
			for(var i = 0; i < this.axes.x.ticks.length; ++i){
				v = this.axes.x.ticks[i].v;
				// Don't show lines on upper and lower bounds.
				if ((v == this.axes.x.min || v == this.axes.x.max) && o.grid.outlineWidth != 0)
					continue;
	
				ctx.moveTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, 0);
				ctx.lineTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, this.plotHeight);
			}
		}
		
		// Draw grid lines in horizontal direction.
		if(o.grid.horizontalLines){
			for(var j = 0; j < this.axes.y.ticks.length; ++j){
				v = this.axes.y.ticks[j].v;
				// Don't show lines on upper and lower bounds.
				if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)
					continue;
	
				ctx.moveTo(0, Math.floor(this.tVert(v)) + ctx.lineWidth/2);
				ctx.lineTo(this.plotWidth, Math.floor(this.tVert(v)) + ctx.lineWidth/2);
			}
		}
		ctx.stroke();
		
		// Draw axis/grid border.
		if(o.grid.outlineWidth != 0) {
			ctx.lineWidth = o.grid.outlineWidth;
			ctx.strokeStyle = o.grid.color;
			ctx.lineJoin = 'round';
			ctx.strokeRect(0, 0, this.plotWidth, this.plotHeight);
		}
		ctx.restore();
		if(o.grid.verticalLines || o.grid.horizontalLines){
			this.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);
		}
	},
	/**
	 * Draws labels for x and y axis.
	 */   
	drawLabels: function(){		
		// Construct fixed width label boxes, which can be styled easily. 
		var noLabels = 0, axis,
			xBoxWidth, i, html, tick,
			options = this.options,
      ctx = this.ctx,
      a = this.axes;
		
		for(i = 0; i < a.x.ticks.length; ++i){
			if (a.x.ticks[i].label) {
				++noLabels;
			}
		}
		xBoxWidth = this.plotWidth / noLabels;
    
		if (!options.HtmlText && this.textEnabled) {
		  var style = {
		    size: options.fontSize,
        adjustAlign: true
		  };

		  // Add x labels.
		  axis = a.x;
		  style.color = axis.options.color || options.grid.color;
		  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
		    tick = axis.ticks[i];
		    if(!tick.label || tick.label.length == 0) continue;
        
        style.angle = Flotr.toRad(axis.options.labelsAngle);
        style.halign = 'c';
        style.valign = 't';
        
		    ctx.drawText(
		      tick.label,
		      this.plotOffset.left + this.tHoz(tick.v, axis), 
		      this.plotOffset.top + this.plotHeight + options.grid.labelMargin,
		      style
		    );
		  }
		  
		  // Add x2 labels.
		  axis = a.x2;
		  style.color = axis.options.color || options.grid.color;
		  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
		    tick = axis.ticks[i];
		    if(!tick.label || tick.label.length == 0) continue;
        
        style.angle = Flotr.toRad(axis.options.labelsAngle);
        style.halign = 'c';
        style.valign = 'b';
        
		    ctx.drawText(
		      tick.label,
		      this.plotOffset.left + this.tHoz(tick.v, axis), 
		      this.plotOffset.top + options.grid.labelMargin,
		      style
		    );
		  }
		  
		  // Add y labels.
		  axis = a.y;
		  style.color = axis.options.color || options.grid.color;
		  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
		    tick = axis.ticks[i];
		    if (!tick.label || tick.label.length == 0) continue;
        
        style.angle = Flotr.toRad(axis.options.labelsAngle);
        style.halign = 'r';
        style.valign = 'm';
        
		    ctx.drawText(
		      tick.label,
		      this.plotOffset.left - options.grid.labelMargin, 
		      this.plotOffset.top + this.tVert(tick.v, axis),
		      style
		    );
		  }
		  
		  // Add y2 labels.
		  axis = a.y2;
		  style.color = axis.options.color || options.grid.color;
		  for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
		    tick = axis.ticks[i];
		    if (!tick.label || tick.label.length == 0) continue;
        
        style.angle = Flotr.toRad(axis.options.labelsAngle);
        style.halign = 'l';
        style.valign = 'm';
        
		    ctx.drawText(
		      tick.label,
		      this.plotOffset.left + this.plotWidth + options.grid.labelMargin, 
		      this.plotOffset.top + this.tVert(tick.v, axis),
		      style
		    );
		    
				ctx.save();
				ctx.strokeStyle = style.color;
				ctx.beginPath();
				ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
				ctx.lineTo(this.plotOffset.left + this.plotWidth,     this.plotOffset.top + this.tVert(tick.v, axis));
				ctx.stroke();
				ctx.restore();
		  }
		} 
		else if (a.x.options.showLabels || 
				     a.x2.options.showLabels || 
				     a.y.options.showLabels || 
				     a.y2.options.showLabels) {
			html = ['<div style="font-size:smaller;color:' + options.grid.color + ';" class="flotr-labels">'];
			
			// Add x labels.
			axis = a.x;
			if (axis.options.showLabels){
				for(i = 0; i < axis.ticks.length; ++i){
					tick = axis.ticks[i];
					if(!tick.label || tick.label.length == 0) continue;
					html.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>');
				}
			}
			
			// Add x2 labels.
			axis = a.x2;
			if (axis.options.showLabels && axis.used){
				for(i = 0; i < axis.ticks.length; ++i){
					tick = axis.ticks[i];
					if(!tick.label || tick.label.length == 0) continue;
					html.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>');
				}
			}
			
			// Add y labels.
			axis = a.y;
			if (axis.options.showLabels){
				for(i = 0; i < axis.ticks.length; ++i){
					tick = axis.ticks[i];
					if (!tick.label || tick.label.length == 0) continue;
					html.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>');
				}
			}
			
			// Add y2 labels.
			axis = a.y2;
			if (axis.options.showLabels && axis.used){
				ctx.save();
				ctx.strokeStyle = axis.options.color || options.grid.color;
				ctx.beginPath();
				
				for(i = 0; i < axis.ticks.length; ++i){
					tick = axis.ticks[i];
					if (!tick.label || tick.label.length == 0) continue;
					html.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>');

					ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
					ctx.lineTo(this.plotOffset.left + this.plotWidth,     this.plotOffset.top + this.tVert(tick.v, axis));
				}
				ctx.stroke();
				ctx.restore();
			}
			
			html.push('</div>');
			this.el.insert(html.join(''));
		}
	},
  /**
   * Draws the title and the subtitle
   */   
  drawTitles: function(){
    var html,
        options = this.options,
        margin = options.grid.labelMargin,
        ctx = this.ctx,
        a = this.axes;
      
    if (!options.HtmlText && this.textEnabled) {
      var style = {
        size: options.fontSize,
        color: options.grid.color,
        halign: 'c'
      };

      // Add subtitle
      if (options.subtitle){
        ctx.drawText(
          options.subtitle,
          this.plotOffset.left + this.plotWidth/2, 
          this.titleHeight + this.subtitleHeight - 2,
          style
        );
      }
      
			style.weight = 1.5;
      style.size *= 1.5;
      
      // Add title
      if (options.title){
        ctx.drawText(
          options.title,
          this.plotOffset.left + this.plotWidth/2, 
          this.titleHeight - 2,
          style
        );
      }
      
      style.weight = 1.8;
      style.size *= 0.8;
      style.adjustAlign = true;
      
			// Add x axis title
			if (a.x.options.title && a.x.used){
				style.halign = 'c';
				style.valign = 't';
				style.angle = Flotr.toRad(a.x.options.titleAngle);
        ctx.drawText(
          a.x.options.title,
          this.plotOffset.left + this.plotWidth/2, 
          this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin,
          style
        );
      }
			
			// Add x2 axis title
			if (a.x2.options.title && a.x2.used){
				style.halign = 'c';
				style.valign = 'b';
				style.angle = Flotr.toRad(a.x2.options.titleAngle);
        ctx.drawText(
          a.x2.options.title,
          this.plotOffset.left + this.plotWidth/2, 
          this.plotOffset.top - a.x2.maxLabel.height - 2 * margin,
          style
        );
      }
			
			// Add y axis title
			if (a.y.options.title && a.y.used){
				style.halign = 'r';
				style.valign = 'm';
				style.angle = Flotr.toRad(a.y.options.titleAngle);
        ctx.drawText(
          a.y.options.title,
          this.plotOffset.left - a.y.maxLabel.width - 2 * margin, 
          this.plotOffset.top + this.plotHeight / 2,
          style
        );
      }
			
			// Add y2 axis title
			if (a.y2.options.title && a.y2.used){
				style.halign = 'l';
				style.valign = 'm';
				style.angle = Flotr.toRad(a.y2.options.titleAngle);
        ctx.drawText(
          a.y2.options.title,
          this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, 
          this.plotOffset.top + this.plotHeight / 2,
          style
        );
      }
    } 
    else {
      html = ['<div style="color:'+options.grid.color+';" class="flotr-titles">'];
      
      // Add title
      if (options.title){
        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>');
      }
      
      // Add subtitle
      if (options.subtitle){
        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>');
      }
      html.push('</div>');
      
      
      html.push('<div class="flotr-axis-title" style="font-weight:bold;">');
			// Add x axis title
			if (a.x.options.title && a.x.used){
				html.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>');
			}
			
			// Add x2 axis title
			if (a.x2.options.title && a.x2.used){
				html.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>');
			}
			
			// Add y axis title
			if (a.y.options.title && a.y.used){
				html.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>');
			}
			
			// Add y2 axis title
			if (a.y2.options.title && a.y2.used){
				html.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>');
			}
			html.push('</div>');
      
      this.el.insert(html.join(''));
    }
  },
	/**
	 * Actually draws the graph.
	 * @param {Object} series - series to draw
	 */
	drawSeries: function(series){
		series = series || this.series;
		
		var drawn = false;
		for(var type in Flotr._registeredTypes){
			if(series[type] && series[type].show){
				this[Flotr._registeredTypes[type]](series);
				drawn = true;
			}
		}
		
		if(!drawn){
			this[Flotr._registeredTypes[this.options.defaultType]](series);
		}
	},
	
	plotLine: function(series, offset){
		var ctx = this.ctx,
		    xa = series.xaxis,
		    ya = series.yaxis,
  			tHoz = this.tHoz.bind(this),
  			tVert = this.tVert.bind(this),
  			data = series.data;
			
		if(data.length < 2) return;

		var prevx = tHoz(data[0][0], xa),
		    prevy = tVert(data[0][1], ya) + offset;

		ctx.beginPath();
		ctx.moveTo(prevx, prevy);
		for(var i = 0; i < data.length - 1; ++i){
			var x1 = data[i][0],   y1 = data[i][1],
			    x2 = data[i+1][0], y2 = data[i+1][1];

      // To allow empty values
      if (y1 === null || y2 === null) continue;
      
			/**
			 * Clip with ymin.
			 */
			if(y1 <= y2 && y1 < ya.min){
				/**
				 * Line segment is outside the drawing area.
				 */
				if(y2 < ya.min) continue;
				
				/**
				 * Compute new intersection point.
				 */
				x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
				y1 = ya.min;
			}else if(y2 <= y1 && y2 < ya.min){
				if(y1 < ya.min) continue;
				x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
				y2 = ya.min;
			}

			/**
			 * Clip with ymax.
			 */ 
			if(y1 >= y2 && y1 > ya.max) {
				if(y2 > ya.max) continue;
				x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
				y1 = ya.max;
			}
			else if(y2 >= y1 && y2 > ya.max){
				if(y1 > ya.max) continue;
				x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
				y2 = ya.max;
			}

			/**
			 * Clip with xmin.
			 */
			if(x1 <= x2 && x1 < xa.min){
				if(x2 < xa.min) continue;
				y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
				x1 = xa.min;
			}else if(x2 <= x1 && x2 < xa.min){
				if(x1 < xa.min) continue;
				y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
				x2 = xa.min;
			}

			/**
			 * Clip with xmax.
			 */
			if(x1 >= x2 && x1 > xa.max){
				if (x2 > xa.max) continue;
				y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
				x1 = xa.max;
			}else if(x2 >= x1 && x2 > xa.max){
				if(x1 > xa.max) continue;
				y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
				x2 = xa.max;
			}

			if(prevx != tHoz(x1, xa) || prevy != tVert(y1, ya) + offset)
				ctx.moveTo(tHoz(x1, xa), tVert(y1, ya) + offset);
			
			prevx = tHoz(x2, xa);
			prevy = tVert(y2, ya) + offset;
			ctx.lineTo(prevx, prevy);
		}
		ctx.stroke();
	},
	/**
	 * Function used to fill
	 * @param {Object} data
	 */
	plotLineArea: function(series, offset){
		var data = series.data;
		if(data.length < 2) return;

		var top, lastX = 0,
			ctx = this.ctx,
	    xa = series.xaxis,
	    ya = series.yaxis,
			tHoz = this.tHoz.bind(this),
			tVert = this.tVert.bind(this),
			bottom = Math.min(Math.max(0, ya.min), ya.max),
			first = true;
		
		ctx.beginPath();
		for(var i = 0; i < data.length - 1; ++i){
			
			var x1 = data[i][0], y1 = data[i][1],
			    x2 = data[i+1][0], y2 = data[i+1][1];
			
			if(x1 <= x2 && x1 < xa.min){
				if(x2 < xa.min) continue;
				y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
				x1 = xa.min;
			}else if(x2 <= x1 && x2 < xa.min){
				if(x1 < xa.min) continue;
				y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
				x2 = xa.min;
			}
								
			if(x1 >= x2 && x1 > xa.max){
				if(x2 > xa.max) continue;
				y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
				x1 = xa.max;
			}else if(x2 >= x1 && x2 > xa.max){
				if (x1 > xa.max) continue;
				y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
				x2 = xa.max;
			}

			if(first){
				ctx.moveTo(tHoz(x1, xa), tVert(bottom, ya) + offset);
				first = false;
			}
			
			/**
			 * Now check the case where both is outside.
			 */
			if(y1 >= ya.max && y2 >= ya.max){
				ctx.lineTo(tHoz(x1, xa), tVert(ya.max, ya) + offset);
				ctx.lineTo(tHoz(x2, xa), tVert(ya.max, ya) + offset);
				continue;
			}else if(y1 <= ya.min && y2 <= ya.min){
				ctx.lineTo(tHoz(x1, xa), tVert(ya.min, ya) + offset);
				ctx.lineTo(tHoz(x2, xa), tVert(ya.min, ya) + offset);
				continue;
			}
			
			/**
			 * Else it's a bit more complicated, there might
			 * be two rectangles and two triangles we need to fill
			 * in; to find these keep track of the current x values.
			 */
			var x1old = x1, x2old = x2;
			
			/**
			 * And clip the y values, without shortcutting.
			 * Clip with ymin.
			 */
			if(y1 <= y2 && y1 < ya.min && y2 >= ya.min){
				x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
				y1 = ya.min;
			}else if(y2 <= y1 && y2 < ya.min && y1 >= ya.min){
				x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
				y2 = ya.min;
			}

			/**
			 * Clip with ymax.
			 */
			if(y1 >= y2 && y1 > ya.max && y2 <= ya.max){
				x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
				y1 = ya.max;
			}else if(y2 >= y1 && y2 > ya.max && y1 <= ya.max){
				x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
				y2 = ya.max;
			}

			/**
			 * If the x value was changed we got a rectangle to fill.
			 */
			if(x1 != x1old){
				top = (y1 <= ya.min) ? top = ya.min : ya.max;
				ctx.lineTo(tHoz(x1old, xa), tVert(top, ya) + offset);
				ctx.lineTo(tHoz(x1, xa), tVert(top, ya) + offset);
			}
		   	
			/**
			 * Fill the triangles.
			 */
			ctx.lineTo(tHoz(x1, xa), tVert(y1, ya) + offset);
			ctx.lineTo(tHoz(x2, xa), tVert(y2, ya) + offset);

			/**
			 * Fill the other rectangle if it's there.
			 */
			if(x2 != x2old){
				top = (y2 <= ya.min) ? ya.min : ya.max;
				ctx.lineTo(tHoz(x2old, xa), tVert(top, ya) + offset);
				ctx.lineTo(tHoz(x2, xa), tVert(top, ya) + offset);
			}

			lastX = Math.max(x2, x2old);
		}
		
		ctx.lineTo(tHoz(lastX, xa), tVert(bottom, ya) + offset);
		ctx.closePath();
		ctx.fill();
	},
	/**
	 * Function: (private) drawSeriesLines
	 * 
	 * Function draws lines series in the canvas element.
	 * 
	 * Parameters:
	 * 		series - Series with options.lines.show = true.
	 * 
	 * Returns:
	 * 		void
	 */
	drawSeriesLines: function(series){
		series = series || this.series;
		var ctx = this.ctx;
		ctx.save();
		ctx.translate(this.plotOffset.left, this.plotOffset.top);
		ctx.lineJoin = 'round';

		var lw = series.lines.lineWidth;
		var sw = series.shadowSize;

		if(sw > 0){
			ctx.lineWidth = sw / 2;

			var offset = lw/2 + ctx.lineWidth/2;
			
			ctx.strokeStyle = "rgba(0,0,0,0.1)";
			this.plotLine(series, offset + sw/2);

			ctx.strokeStyle = "rgba(0,0,0,0.2)";
			this.plotLine(series, offset);

			if(series.lines.fill) {
				ctx.fillStyle = "rgba(0,0,0,0.05)";
				this.plotLineArea(series, offset + sw/2);
			}
		}

		ctx.lineWidth = lw;
		ctx.strokeStyle = series.color;
		if(series.lines.fill){
			ctx.fillStyle = series.lines.fillColor != null ? series.lines.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.lines.fillOpacity).toString();
			this.plotLineArea(series, 0);
		}

		this.plotLine(series, 0);
		ctx.restore();
	},
	/**
	 * Function: drawSeriesPoints
	 * 
	 * Function draws point series in the canvas element.
	 * 
	 * Parameters:
	 * 		series - Series with options.points.show = true.
	 * 
	 * Returns:
	 * 		void
	 */
	drawSeriesPoints: function(series) {
		var ctx = this.ctx;
		
		ctx.save();
		ctx.translate(this.plotOffset.left, this.plotOffset.top);

		var lw = series.lines.lineWidth;
		var sw = series.shadowSize;
		
		if(sw > 0){
			ctx.lineWidth = sw / 2;
      
			ctx.strokeStyle = 'rgba(0,0,0,0.1)';
			this.plotPointShadows(series, sw/2 + ctx.lineWidth/2, series.points.radius);

			ctx.strokeStyle = 'rgba(0,0,0,0.2)';
			this.plotPointShadows(series, ctx.lineWidth/2, series.points.radius);
		}

		ctx.lineWidth = series.points.lineWidth;
		ctx.strokeStyle = series.color;
		ctx.fillStyle = series.points.fillColor != null ? series.points.fillColor : series.color;
		this.plotPoints(series, series.points.radius, series.points.fill);
		ctx.restore();
	},
	plotPoints: function (series, radius, fill) {
    var xa = series.xaxis,
        ya = series.yaxis,
		    ctx = this.ctx, i,
		    data = series.data;
			
		for(i = data.length - 1; i > -1; --i){
			var x = data[i][0], y = data[i][1];
			if(x < xa.min || x > xa.max || y < ya.min || y > ya.max)
				continue;
			
			ctx.beginPath();
			ctx.arc(this.tHoz(x, xa), this.tVert(y, ya), radius, 0, 2 * Math.PI, true);
			if(fill) ctx.fill();
			ctx.stroke();
		}
	},
	plotPointShadows: function(series, offset, radius){
    var xa = series.xaxis,
        ya = series.yaxis,
		    ctx = this.ctx, i,
		    data = series.data;
			
		for(i = data.length - 1; i > -1; --i){
			var x = data[i][0], y = data[i][1];
			if (x < xa.min || x > xa.max || y < ya.min || y > ya.max)
				continue;
			ctx.beginPath();
			ctx.arc(this.tHoz(x, xa), this.tVert(y, ya) + offset, radius, 0, Math.PI, false);
			ctx.stroke();
		}
	},
	/**
	 * Function: drawSeriesBars
	 * 
	 * Function draws bar series in the canvas element.
	 * 
	 * Parameters:
	 * 		series - Series with options.bars.show = true.
	 * 
	 * Returns:
	 * 		void
	 */
	drawSeriesBars: function(series) {
		var ctx = this.ctx,
			bw = series.bars.barWidth,
			lw = Math.min(series.bars.lineWidth, bw);
		
		ctx.save();
		ctx.translate(this.plotOffset.left, this.plotOffset.top);
		ctx.lineJoin = 'miter';

		/**
		 * @todo linewidth not interpreted the right way.
		 */
		ctx.lineWidth = lw;
		ctx.strokeStyle = series.color;
    
		this.plotBarsShadows(series, bw, 0, series.bars.fill);

		if(series.bars.fill){
			ctx.fillStyle = series.bars.fillColor != null ? series.bars.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.bars.fillOpacity).toString();
		}
    
		this.plotBars(series, bw, 0, series.bars.fill);
		ctx.restore();
	},
	plotBars: function(series, barWidth, offset, fill){
		var data = series.data;
		if(data.length < 1) return;
		
    var xa = series.xaxis,
        ya = series.yaxis,
  			ctx = this.ctx,
  			tHoz = this.tHoz.bind(this),
  			tVert = this.tVert.bind(this);

		for(var i = 0; i < data.length; i++){
			var x = data[i][0],
			    y = data[i][1];
			var drawLeft = true, drawTop = true, drawRight = true;
			
			// Stacked bars
			var stackOffset = 0;
			if(series.bars.stacked) {
			  xa.values.each(function(o, v) {
			    if (v == x) {
			      stackOffset = o.stack || 0;
			      o.stack = stackOffset + y;
			    }
			  });
			}

			// @todo: fix horizontal bars support
			// Horizontal bars
			if(series.bars.horizontal)
				var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
			else 
				var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;

			if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
				continue;

			if(left < xa.min){
				left = xa.min;
				drawLeft = false;
			}

			if(right > xa.max){
				right = xa.max;
				if (xa.lastSerie != series && series.bars.horizontal)
					drawTop = false;
			}

			if(bottom < ya.min)
				bottom = ya.min;

			if(top > ya.max){
				top = ya.max;
				if (ya.lastSerie != series && !series.bars.horizontal)
					drawTop = false;
			}
      
			/**
			 * Fill the bar.
			 */
			if(fill){
				ctx.beginPath();
				ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
				ctx.lineTo(tHoz(left, xa), tVert(top, ya) + offset);
				ctx.lineTo(tHoz(right, xa), tVert(top, ya) + offset);
				ctx.lineTo(tHoz(right, xa), tVert(bottom, ya) + offset);
				ctx.fill();
			}

			/**
			 * Draw bar outline/border.
			 */
			if(series.bars.lineWidth != 0 && (drawLeft || drawRight || drawTop)){
				ctx.beginPath();
				ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
				
				ctx[drawLeft ?'lineTo':'moveTo'](tHoz(left, xa), tVert(top, ya) + offset);
				ctx[drawTop  ?'lineTo':'moveTo'](tHoz(right, xa), tVert(top, ya) + offset);
				ctx[drawRight?'lineTo':'moveTo'](tHoz(right, xa), tVert(bottom, ya) + offset);
				         
				ctx.stroke();
			}
		}
	},
  plotBarsShadows: function(series, barWidth, offset){
		var data = series.data;
    if(data.length < 1) return;
    
    var xa = series.xaxis,
        ya = series.yaxis,
        ctx = this.ctx,
        tHoz = this.tHoz.bind(this),
        tVert = this.tVert.bind(this),
        sw = this.options.shadowSize;

    for(var i = 0; i < data.length; i++){
      var x = data[i][0],
          y = data[i][1];
      
      // Stacked bars
      var stackOffset = 0;
			if(series.bars.stacked) {
			  xa.values.each(function(o, v) {
			    if (v == x) {
			      stackOffset = o.stackShadow || 0;
			      o.stackShadow = stackOffset + y;
			    }
			  });
			}
      
      // Horizontal bars
      if(series.bars.horizontal) 
        var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
      else 
        var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;

      if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
        continue;

      if(left < xa.min)   left = xa.min;
      if(right > xa.max)  right = xa.max;
      if(bottom < ya.min) bottom = ya.min;
      if(top > ya.max)    top = ya.max;
      
      var width =  tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);
      var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));

      ctx.fillStyle = 'rgba(0,0,0,0.05)';
      ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);
    }
  },
	/**
	 * Function: drawSeriesCandles
	 * 
	 * Function draws candles series in the canvas element.
	 * 
	 * Parameters:
	 * 		series - Series with options.candles.show = true.
	 * 
	 * Returns:
	 * 		void
	 */
	drawSeriesCandles: function(series) {
		var ctx = this.ctx,
			  bw = series.candles.candleWidth;
		
		ctx.save();
		ctx.translate(this.plotOffset.left, this.plotOffset.top);
		ctx.lineJoin = 'miter';

		/**
		 * @todo linewidth not interpreted the right way.
		 */
		ctx.lineWidth = series.candles.lineWidth;
		this.plotCandlesShadows(series, bw/2);
		this.plotCandles(series, bw/2);
		
		ctx.restore();
	},
	plotCandles: function(series, offset){
		var data = series.data;
		if(data.length < 1) return;
		
    var xa = series.xaxis,
        ya = series.yaxis,
  			ctx = this.ctx,
  			tHoz = this.tHoz.bind(this),
  			tVert = this.tVert.bind(this);

		for(var i = 0; i < data.length; i++){
      var d     = data[i],
  		    x     = d[0],
  		    open  = d[1],
  		    high  = d[2],
  		    low   = d[3],
  		    close = d[4];

			var left    = x,
			    right   = x + series.candles.candleWidth,
          bottom  = Math.max(ya.min, low),
	        top     = Math.min(ya.max, high),
          bottom2 = Math.max(ya.min, Math.min(open, close)),
	        top2    = Math.min(ya.max, Math.max(open, close));

			if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
				continue;

			var color = series.candles[open>close?'downFillColor':'upFillColor'];
			/**
			 * Fill the candle.
			 */
			if(series.candles.fill && !series.candles.barcharts){
				ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.candles.fillOpacity).toString();
				ctx.fillRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));
			}

			/**
			 * Draw candle outline/border, high, low.
			 */
			if(series.candles.lineWidth || series.candles.wickLineWidth){
				var x, y, pixelOffset = (series.candles.wickLineWidth % 2) / 2;

				x = Math.floor(tHoz((left + right) / 2), xa) + pixelOffset;
				
			  ctx.save();
			  ctx.strokeStyle = color;
			  ctx.lineWidth = series.candles.wickLineWidth;
			  ctx.lineCap = 'butt';
			  
				if (series.candles.barcharts) {
					ctx.beginPath();
					
					ctx.moveTo(x, Math.floor(tVert(top, ya) + offset));
					ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));
					
					y = Math.floor(tVert(open, ya) + offset)+0.5;
					ctx.moveTo(Math.floor(tHoz(left, xa))+pixelOffset, y);
					ctx.lineTo(x, y);
					
					y = Math.floor(tVert(close, ya) + offset)+0.5;
					ctx.moveTo(Math.floor(tHoz(right, xa))+pixelOffset, y);
					ctx.lineTo(x, y);
				} 
				else {
  				ctx.strokeRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));

  				ctx.beginPath();
  				ctx.moveTo(x, Math.floor(tVert(top2,    ya) + offset));
  				ctx.lineTo(x, Math.floor(tVert(top,     ya) + offset));
  				ctx.moveTo(x, Math.floor(tVert(bottom2, ya) + offset));
  				ctx.lineTo(x, Math.floor(tVert(bottom,  ya) + offset));
				}
				
				ctx.stroke();
				ctx.restore();
			}
		}
	},
  plotCandlesShadows: function(series, offset){
		var data = series.data;
    if(data.length < 1 || series.candles.barcharts) return;
    
    var xa = series.xaxis,
        ya = series.yaxis,
        tHoz = this.tHoz.bind(this),
        tVert = this.tVert.bind(this),
        sw = this.options.shadowSize;

    for(var i = 0; i < data.length; i++){
      var d     = data[i],
      		x     = d[0],
	        open  = d[1],
	        high  = d[2],
	        low   = d[3],
	        close = d[4];
      
			var left   = x,
	        right  = x + series.candles.candleWidth,
          bottom = Math.max(ya.min, Math.min(open, close)),
	        top    = Math.min(ya.max, Math.max(open, close));

      if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
        continue;

      var width =  tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);
      var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));

      this.ctx.fillStyle = 'rgba(0,0,0,0.05)';
      this.ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);
    }
  },
  /**
   * Function: drawSeriesPie
   * 
   * Function draws a pie in the canvas element.
   * 
   * Parameters:
   *    series - Series with options.pie.show = true.
   * 
   * Returns:
   *    void
   */
  drawSeriesPie: function(series) {
    if (!this.options.pie.drawn) {
    var ctx = this.ctx,
        options = this.options,
        lw = series.pie.lineWidth,
        sw = series.shadowSize,
        data = series.data,
        radius = (Math.min(this.canvasWidth, this.canvasHeight) * series.pie.sizeRatio) / 2,
        html = [];
    
    var vScale = 1;//Math.cos(series.pie.viewAngle);
    var plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;
    
    var style = {
      size: options.fontSize*1.2,
      color: options.grid.color,
      weight: 1.5
    };
    
    var center = {
    
Download .txt
gitextract_ps1zfdc6/

├── .eslintrc
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── index.js
├── input-scripts/
│   ├── coolclock/
│   │   ├── coolclock.js
│   │   ├── excanvas.js
│   │   └── moreskins.js
│   ├── flotr/
│   │   ├── flotr-0.2.0-alpha.js
│   │   ├── flotr.debug-0.2.0-alpha.js
│   │   └── lib/
│   │       ├── base64.js
│   │       ├── canvas2image.js
│   │       ├── canvastext.js
│   │       ├── excanvas.js
│   │       └── prototype-1.6.0.2.js
│   ├── fullcalendar/
│   │   ├── fullcalendar/
│   │   │   ├── fullcalendar.css
│   │   │   ├── fullcalendar.js
│   │   │   ├── fullcalendar.print.css
│   │   │   └── gcal.js
│   │   └── lib/
│   │       └── jquery-2.1.0.js
│   └── simple-scripts/
│       ├── function_function.js
│       ├── functioncall-arithmetic.js
│       ├── jQuery.js
│       ├── or_function.js
│       └── use_before_definition.js
├── js-callgraph.js
├── package.json
├── saveSvgAsPng.js
├── scripts/
│   ├── install-hooks
│   └── pre-commit
├── src/
│   ├── astutil.js
│   ├── bindings.js
│   ├── bitset.js
│   ├── callbackCounter.js
│   ├── callgraph.js
│   ├── dftc.js
│   ├── diagnostics.js
│   ├── flowgraph.js
│   ├── graph.js
│   ├── harness.js
│   ├── input-2.js
│   ├── linkedList.js
│   ├── module.js
│   ├── natives.js
│   ├── numset.js
│   ├── olist.js
│   ├── pessimistic.js
│   ├── requireJsGraph.js
│   ├── runner.js
│   ├── semioptimistic.js
│   ├── set.js
│   ├── srcPreprocessor.js
│   ├── symtab.js
│   ├── tests.js
│   ├── underscore.js
│   └── utils.js
└── tests/
    ├── README.md
    ├── basics/
    │   ├── arrow.js
    │   ├── arrow.truth
    │   ├── assignment.js
    │   ├── assignment.truth
    │   ├── global-as-prop.js
    │   ├── global-as-prop.truth
    │   ├── local-is-fine.js
    │   ├── local-is-fine.truth
    │   ├── method-def.js
    │   └── method-def.truth
    ├── callgraph.py
    ├── classes/
    │   ├── anonymous-class.js
    │   ├── basic-class.js
    │   ├── basic-class.truth
    │   ├── basic-class2.js
    │   ├── basic-class2.truth
    │   ├── class-expression1.js
    │   ├── class-expression1.truth
    │   ├── class-expression2.js
    │   ├── class-expression2.truth
    │   ├── class.js
    │   ├── class.truth
    │   ├── export-class-expression1.js
    │   ├── export-class-expression2.js
    │   ├── import-anonymous-class.js
    │   ├── import-anonymous-class.truth
    │   ├── import-class-expression1.js
    │   ├── import-class-expression1.truth
    │   ├── import-class-expression2.js
    │   ├── import-class-expression2.truth
    │   ├── outer-fn.js
    │   └── outer-fn.truth
    ├── creating-vue-compiled.txt
    ├── es6/
    │   ├── array-pattern.js
    │   ├── array-pattern.truth
    │   ├── array-pattern2.js
    │   ├── array-pattern2.truth
    │   ├── array-pattern3.js
    │   ├── array-pattern3.truth
    │   ├── array-pattern4.js
    │   ├── array-pattern4.truth
    │   ├── binding-pattern-global.js
    │   ├── binding-pattern-global.truth
    │   ├── destructured-parameter.js
    │   ├── destructured-parameter.truth
    │   ├── destructured-parameter2.js
    │   ├── destructured-parameter2.truth
    │   ├── destructured-parameter3.js
    │   ├── destructured-parameter3.truth
    │   ├── lib.js
    │   ├── main.js
    │   ├── main.truth
    │   ├── object-pattern.js
    │   ├── object-pattern.truth
    │   ├── object-pattern2.js
    │   ├── object-pattern2.truth
    │   ├── object-pattern3.js
    │   └── object-pattern3.truth
    ├── ground_truths/
    │   ├── create-component.txt
    │   ├── create-element.txt
    │   ├── ground-truth.txt
    │   ├── patch.txt
    │   └── vnode.txt
    ├── import-export/
    │   ├── define/
    │   │   ├── arrow-func-no-block-statement-module.js
    │   │   ├── arrow-func-no-block-statement-require.js
    │   │   ├── arrow-func-no-block-statement-require.truth
    │   │   ├── define-module.js
    │   │   ├── define-require.js
    │   │   └── define-require.truth
    │   ├── es6/
    │   │   ├── es6-cyclic-dependencies1.js
    │   │   ├── es6-cyclic-dependencies1.truth
    │   │   ├── es6-cyclic-dependencies2.js
    │   │   ├── es6-cyclic-dependencies2.truth
    │   │   ├── es6-export-default.js
    │   │   ├── es6-export-fns.js
    │   │   ├── es6-export-hasOwnProperty.js
    │   │   ├── es6-export-mixed.js
    │   │   ├── es6-import-default.js
    │   │   ├── es6-import-default.truth
    │   │   ├── es6-import-entire.js
    │   │   ├── es6-import-entire.truth
    │   │   ├── es6-import-hasOwnProperty.js
    │   │   ├── es6-import-hasOwnProperty.truth
    │   │   ├── es6-import-mixed.js
    │   │   ├── es6-import-mixed.truth
    │   │   ├── es6-import-named.js
    │   │   ├── es6-import-named.truth
    │   │   ├── es6-import-redirect.js
    │   │   ├── es6-import-redirect.truth
    │   │   └── redirect/
    │   │       ├── auth.js
    │   │       ├── index.js
    │   │       ├── project.js
    │   │       └── search.js
    │   └── module.exports/
    │       ├── module-exports-module.js
    │       ├── module-exports-module2.js
    │       ├── module-exports-require.js
    │       ├── module-exports-require.truth
    │       ├── module-exports-require2.js
    │       └── module-exports-require2.truth
    ├── jest/
    │   ├── graph.test.js
    │   └── linkedList.test.js
    ├── limits/
    │   ├── history.js
    │   ├── history.truth
    │   ├── overload.js
    │   └── overload.truth
    ├── process.py
    ├── required_files.py
    ├── test.py
    ├── typescript/
    │   ├── simple.truth
    │   └── simple.ts
    ├── unexpected/
    │   ├── stringiterator.js
    │   └── stringiterator.truth
    ├── unhandled/
    │   ├── classes/
    │   │   ├── class-compiled.js
    │   │   ├── class-compiled.truth
    │   │   ├── class-compiled2.js
    │   │   ├── class-compiled2.truth
    │   │   ├── class-getter.js
    │   │   └── class-getter.truth
    │   └── limits/
    │       ├── history.js
    │       ├── history.truth
    │       ├── overload.js
    │       └── overload.truth
    └── vue/
        ├── TodoList.truth
        ├── TodoList.vue
        └── example.vue
Download .txt
SYMBOL INDEX (422 symbols across 79 files)

FILE: index.js
  constant JCG (line 9) | const JCG = require("./src/runner");

FILE: input-scripts/coolclock/excanvas.js
  function onPropertyChange (line 148) | function onPropertyChange(e) {
  function onResize (line 163) | function onResize(e) {
  function createMatrixIdentity (line 181) | function createMatrixIdentity() {
  function matrixMultiply (line 189) | function matrixMultiply(m1, m2) {
  function copyState (line 206) | function copyState(o1, o2) {
  function processStyle (line 221) | function processStyle(styleString) {
  function processLineCap (line 245) | function processLineCap(lineCap) {
  function CanvasRenderingContext2D_ (line 263) | function CanvasRenderingContext2D_(surfaceElement) {
  function CanvasGradient_ (line 762) | function CanvasGradient_(aType) {
  function CanvasPattern_ (line 775) | function CanvasPattern_() {}

FILE: input-scripts/flotr/flotr-0.2.0-alpha.js
  function A (line 2) | function A(){B.show();$(document).stopObserving("mousemove",A)}

FILE: input-scripts/flotr/flotr.debug-0.2.0-alpha.js
  function cancelContextMenu (line 2537) | function cancelContextMenu () {

FILE: input-scripts/flotr/lib/base64.js
  function base64encode (line 26) | function base64encode(str) {
  function base64decode (line 60) | function base64decode(str) {

FILE: input-scripts/flotr/lib/excanvas.js
  function getContext (line 56) | function getContext() {
  function bind (line 79) | function bind(f, obj, var_args) {
  function onPropertyChange (line 171) | function onPropertyChange(e) {
  function onResize (line 186) | function onResize(e) {
  function createMatrixIdentity (line 204) | function createMatrixIdentity() {
  function matrixMultiply (line 212) | function matrixMultiply(m1, m2) {
  function copyState (line 229) | function copyState(o1, o2) {
  function processStyle (line 246) | function processStyle(styleString) {
  function processLineCap (line 270) | function processLineCap(lineCap) {
  function CanvasRenderingContext2D_ (line 288) | function CanvasRenderingContext2D_(surfaceElement) {
  function bezierCurveTo (line 355) | function bezierCurveTo(self, cp1, cp2, p) {
  function CanvasGradient_ (line 856) | function CanvasGradient_(aType) {
  function CanvasPattern_ (line 874) | function CanvasPattern_() {}

FILE: input-scripts/flotr/lib/prototype-1.6.0.2.js
  function klass (line 47) | function klass() {
  function $A (line 807) | function $A(iterable) {
  function $w (line 936) | function $w(string) {
  function $H (line 984) | function $H(object) {
  function toQueryPair (line 990) | function toQueryPair(key, value) {
  function $ (line 1502) | function $(element) {
  function stripAlpha (line 2270) | function stripAlpha(filter){
  function extend (line 2608) | function extend(tagName) {
  function copy (line 2615) | function copy(methods, destination, onlyIfAbsent) {
  function findDOMClass (line 2625) | function findDOMClass(tagName) {
  function $$ (line 3372) | function $$() {
  function getEventID (line 3846) | function getEventID(element) {
  function getDOMEventName (line 3852) | function getDOMEventName(eventName) {
  function getCacheForID (line 3857) | function getCacheForID(id) {
  function getWrappersForEventName (line 3861) | function getWrappersForEventName(id, eventName) {
  function createWrapper (line 3866) | function createWrapper(element, eventName, handler) {
  function findWrapper (line 3885) | function findWrapper(id, eventName, handler) {
  function destroyWrapper (line 3890) | function destroyWrapper(id, eventName, handler) {
  function destroyCache (line 3896) | function destroyCache() {
  function fireContentLoadedEvent (line 4003) | function fireContentLoadedEvent() {
  function iter (line 4152) | function iter(name) {

FILE: input-scripts/fullcalendar/fullcalendar/fullcalendar.js
  function setDefaults (line 179) | function setDefaults(d) {
  function Calendar (line 188) | function Calendar(element, options, eventSources) {
  function Header (line 725) | function Header(calendar, options) {
  function EventManager (line 896) | function EventManager(options, _sources) {
  function addYears (line 1321) | function addYears(d, n, keepTime) {
  function addMonths (line 1330) | function addMonths(d, n, keepTime) { // prevents day overflow/underflow
  function addDays (line 1348) | function addDays(d, n, keepTime) { // deals with daylight savings
  function fixDate (line 1364) | function fixDate(d, check) { // force d to be on check's YMD, for daylig...
  function addMinutes (line 1373) | function addMinutes(d, n) {
  function clearTime (line 1379) | function clearTime(d) {
  function cloneDate (line 1388) | function cloneDate(d, dontKeepTime) {
  function zeroDate (line 1396) | function zeroDate() { // returns a Date with time 00:00:00 and dateOfMon...
  function dayDiff (line 1405) | function dayDiff(d1, d2) { // d1 - d2
  function setYMD (line 1410) | function setYMD(date, y, m, d) {
  function parseDate (line 1431) | function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
  function parseISO8601 (line 1452) | function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to...
  function parseTime (line 1506) | function parseTime(s) { // returns minutes since start of day
  function formatDate (line 1533) | function formatDate(date, format, options) {
  function formatDates (line 1538) | function formatDates(date1, date2, format, options) {
  function iso8601Week (line 1663) | function iso8601Week(date) {
  function exclEndDay (line 1686) | function exclEndDay(event) {
  function _exclEndDay (line 1695) | function _exclEndDay(end, allDay) {
  function lazySegBind (line 1707) | function lazySegBind(container, segs, bindHandlers) {
  function setOuterWidth (line 1731) | function setOuterWidth(element, width, includeMargins) {
  function setOuterHeight (line 1739) | function setOuterHeight(element, height, includeMargins) {
  function hsides (line 1747) | function hsides(element, includeMargins) {
  function hpadding (line 1752) | function hpadding(element) {
  function hmargins (line 1758) | function hmargins(element) {
  function hborders (line 1764) | function hborders(element) {
  function vsides (line 1770) | function vsides(element, includeMargins) {
  function vpadding (line 1775) | function vpadding(element) {
  function vmargins (line 1781) | function vmargins(element) {
  function vborders (line 1787) | function vborders(element) {
  function noop (line 1802) | function noop() { }
  function dateCompare (line 1805) | function dateCompare(a, b) {
  function arrayMax (line 1810) | function arrayMax(a) {
  function zeroPad (line 1815) | function zeroPad(n) {
  function smartProperty (line 1820) | function smartProperty(obj, name) { // get a camel-cased/namespaced prop...
  function htmlEscape (line 1836) | function htmlEscape(s) {
  function disableTextSelection (line 1846) | function disableTextSelection(element) {
  function markFirstLast (line 1864) | function markFirstLast(e) {
  function setDayID (line 1875) | function setDayID(cell, date) {
  function getSkinCss (line 1883) | function getSkinCss(event, opt) {
  function applyAll (line 1920) | function applyAll(functions, thisObj, args) {
  function firstDefined (line 1935) | function firstDefined() {
  function MonthView (line 1948) | function MonthView(element, calendar) {
  function BasicWeekView (line 2012) | function BasicWeekView(element, calendar) {
  function BasicDayView (line 2068) | function BasicDayView(element, calendar) {
  function BasicView (line 2112) | function BasicView(element, calendar, viewName) {
  function BasicEventRenderer (line 2629) | function BasicEventRenderer() {
  function AgendaWeekView (line 2660) | function AgendaWeekView(element, calendar) {
  function AgendaDayView (line 2715) | function AgendaDayView(element, calendar) {
  function AgendaView (line 2777) | function AgendaView(element, calendar, viewName) {
  function AgendaEventRenderer (line 3650) | function AgendaEventRenderer() {
  function placeSlotSegs (line 4338) | function placeSlotSegs(segs) {
  function buildSlotSegLevels (line 4362) | function buildSlotSegLevels(segs) {
  function computeForwardSlotSegs (line 4386) | function computeForwardSlotSegs(levels) {
  function computeSlotSegPressures (line 4408) | function computeSlotSegPressures(seg) {
  function computeSlotSegCoords (line 4442) | function computeSlotSegCoords(seg, seriesBackwardPressure, seriesBackwar...
  function flattenSlotSegLevels (line 4479) | function flattenSlotSegLevels(levels) {
  function computeSlotSegCollisions (line 4498) | function computeSlotSegCollisions(seg, otherSegs, results) {
  function isSlotSegCollision (line 4512) | function isSlotSegCollision(seg1, seg2) {
  function compareForwardSlotSegs (line 4518) | function compareForwardSlotSegs(seg1, seg2) {
  function compareSlotSegs (line 4530) | function compareSlotSegs(seg1, seg2) {
  function View (line 4540) | function View(element, calendar, viewName) {
  function DayEventRenderer (line 5081) | function DayEventRenderer() {
  function isDaySegmentCollision (line 5798) | function isDaySegmentCollision(segment, otherSegments) {
  function segmentElementEach (line 5812) | function segmentElementEach(segments, callback) { // TODO: use in Agenda...
  function compareDaySegments (line 5824) | function compareDaySegments(a, b) {
  function SelectionManager (line 5836) | function SelectionManager() {
  function OverlayManager (line 5934) | function OverlayManager() {
  function CoordinateGrid (line 5973) | function CoordinateGrid(buildFunc) {
  function HoverListener (line 6021) | function HoverListener(coordinateGrid) {
  function _fixUIEvent (line 6073) | function _fixUIEvent(event) { // for issue 1168
  function HorizontalPositionCache (line 6081) | function HorizontalPositionCache(getElement) {

FILE: input-scripts/fullcalendar/fullcalendar/gcal.js
  function transformOptions (line 36) | function transformOptions(sourceOptions, start, end) {

FILE: input-scripts/fullcalendar/lib/jquery-2.1.0.js
  function isArraylike (line 537) | function isArraylike( obj ) {
  function Sizzle (line 732) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 847) | function createCache() {
  function markFunction (line 865) | function markFunction( fn ) {
  function assert (line 874) | function assert( fn ) {
  function addHandle (line 896) | function addHandle( attrs, handler ) {
  function siblingCheck (line 911) | function siblingCheck( a, b ) {
  function createInputPseudo (line 938) | function createInputPseudo( type ) {
  function createButtonPseudo (line 949) | function createButtonPseudo( type ) {
  function createPositionalPseudo (line 960) | function createPositionalPseudo( fn ) {
  function testContext (line 983) | function testContext( context ) {
  function setFilters (line 1977) | function setFilters() {}
  function tokenize (line 1981) | function tokenize( selector, parseOnly ) {
  function toSelector (line 2048) | function toSelector( tokens ) {
  function addCombinator (line 2058) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 2111) | function elementMatcher( matchers ) {
  function condense (line 2125) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 2146) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 2239) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 2294) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function multipleContexts (line 2420) | function multipleContexts( selector, contexts, results ) {
  function select (line 2429) | function select( selector, context, results, seed ) {
  function winnow (line 2581) | function winnow( elements, qualifier, not ) {
  function sibling (line 2906) | function sibling( cur, dir ) {
  function createOptions (line 2984) | function createOptions( options ) {
  function completed (line 3377) | function completed() {
  function Data (line 3482) | function Data() {
  function dataAttr (line 3674) | function dataAttr( elem, key, data ) {
  function returnTrue (line 4002) | function returnTrue() {
  function returnFalse (line 4006) | function returnFalse() {
  function safeActiveElement (line 4010) | function safeActiveElement() {
  function manipulationTarget (line 4873) | function manipulationTarget( elem, content ) {
  function disableScript (line 4883) | function disableScript( elem ) {
  function restoreScript (line 4887) | function restoreScript( elem ) {
  function setGlobalEval (line 4900) | function setGlobalEval( elems, refElements ) {
  function cloneCopyEvent (line 4911) | function cloneCopyEvent( src, dest ) {
  function getAll (line 4945) | function getAll( context, tag ) {
  function fixInput (line 4956) | function fixInput( src, dest ) {
  function actualDisplay (line 5414) | function actualDisplay( name, doc ) {
  function defaultDisplay (line 5435) | function defaultDisplay( nodeName ) {
  function curCSS (line 5475) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 5523) | function addGetHookIf( conditionFn, hookFn ) {
  function computePixelPositionAndBoxSizingReliable (line 5562) | function computePixelPositionAndBoxSizingReliable() {
  function vendorPropName (line 5657) | function vendorPropName( style, name ) {
  function setPositiveNumber (line 5679) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 5687) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 5726) | function getWidthOrHeight( elem, name, extra ) {
  function showHide (line 5770) | function showHide( elements, show ) {
  function Tween (line 6073) | function Tween( elem, options, prop, end, easing ) {
  function createFxNow (line 6242) | function createFxNow() {
  function genFx (line 6250) | function genFx( type, includeWidth ) {
  function createTween (line 6270) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 6284) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 6411) | function propFilter( props, specialEasing ) {
  function Animation (line 6448) | function Animation( elem, properties, options ) {
  function addToPrefiltersOrTransports (line 7505) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 7537) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 7564) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 7584) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 7640) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 8097) | function done( status, nativeStatusText, responses, headers ) {
  function buildParams (line 8349) | function buildParams( prefix, obj, traditional, add ) {
  function getWindow (line 8827) | function getWindow( elem ) {

FILE: input-scripts/simple-scripts/function_function.js
  function defineProperties (line 2) | function defineProperties(target, props) {
  function _classCallCheck (line 23) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function Animal (line 26) | function Animal(name, color) {

FILE: input-scripts/simple-scripts/functioncall-arithmetic.js
  function f (line 3) | function f(a) {
  function j (line 10) | function j(b) {
  function g (line 14) | function g(h, y) {

FILE: input-scripts/simple-scripts/jQuery.js
  function jQuery (line 2) | function jQuery(n) {

FILE: input-scripts/simple-scripts/use_before_definition.js
  function add (line 6) | function add(x, y) {

FILE: js-callgraph.js
  constant JCG (line 12) | const JCG = require("./src/runner");

FILE: src/astutil.js
  function visit (line 17) | function visit(root, visitor) {
  function visitWithState (line 40) | function visitWithState(root, visitor) {
  function init (line 70) | function init(root) {
  function basename (line 195) | function basename(filename) {
  function isAnon (line 204) | function isAnon(funcName) {
  function funcname (line 209) | function funcname(func) {
  function encFuncName (line 219) | function encFuncName(encFunc) {
  function ppPos (line 229) | function ppPos(nd) {
  function astFromFiles (line 234) | function astFromFiles(files) {
  function astFromSrc (line 258) | function astFromSrc(fname, src) {
  function reportError (line 271) | function reportError(msg, err) {
  function parse (line 282) | function parse(src) {
  function buildProgram (line 299) | function buildProgram (fname, src) {
  function getFunctions (line 363) | function getFunctions(root, src) {
  function isModuleExports (line 427) | function isModuleExports(nd) {
  function isCallTo (line 460) | function isCallTo(nd, fn_name) {
  function getReturnValues (line 501) | function getReturnValues(fn) {
  function isFunction (line 568) | function isFunction(nd) {

FILE: src/bindings.js
  function addBindings (line 20) | function addBindings(ast) {

FILE: src/bitset.js
  function countBitsInWord (line 21) | function countBitsInWord(w) {
  function countBits (line 30) | function countBits(a) {
  function size (line 38) | function size(a) {
  function contains (line 51) | function contains(a, x) {
  function createSingletonBitset (line 67) | function createSingletonBitset(x) {
  function add (line 78) | function add(a, x) {
  function addAll (line 95) | function addAll(a, b) {
  function remove (line 115) | function remove(a, x) {
  function removeAll (line 128) | function removeAll(a, b) {
  function copy (line 145) | function copy(a) {
  function iter (line 152) | function iter(a, cb) {
  function map (line 165) | function map(a, f) {
  function some (line 181) | function some(a, f) {
  function all (line 196) | function all(a, f) {
  function fromArray (line 211) | function fromArray(ary) {
  function toArray (line 219) | function toArray(a) {

FILE: src/callbackCounter.js
  function findEnclosingFunctionParameter (line 43) | function findEnclosingFunctionParameter(node, functionName) {
  function findFirst (line 57) | function findFirst(array, predicate) {
  function isParameterWithName (line 68) | function isParameterWithName(functionName) {

FILE: src/callgraph.js
  function extractCG (line 22) | function extractCG(ast, flow_graph) {

FILE: src/dftc.js
  function visit1 (line 49) | function visit1(i) {
  function visit2 (line 97) | function visit2(i) {

FILE: src/flowgraph.js
  function addIntraproceduralFlowGraphEdges (line 25) | function addIntraproceduralFlowGraphEdges(ast, flow_graph) {
  function vertexFor (line 165) | function vertexFor(nd) {
  function varVertex (line 196) | function varVertex(nd) {
  function propVertex (line 214) | function propVertex(nd) {
  function globVertex (line 238) | function globVertex(nd) {
  function nativeVertex (line 260) | function nativeVertex(name) {
  function getNativeVertices (line 268) | function getNativeVertices() {
  function unknownVertex (line 278) | function unknownVertex() {
  function funcVertex (line 283) | function funcVertex(fn) {
  function parmVertex (line 297) | function parmVertex(fn, i) {
  function retVertex (line 312) | function retVertex(fn) {
  function calleeVertex (line 327) | function calleeVertex(nd) {
  function argVertex (line 342) | function argVertex(nd, i) {
  function resVertex (line 367) | function resVertex(nd) {
  function exprVertex (line 381) | function exprVertex(nd) {

FILE: src/graph.js
  class BasicGraph (line 19) | class BasicGraph {
    method constructor (line 20) | constructor() {
    method addNode (line 25) | addNode(node) {
    method removeNode (line 32) | removeNode(node) {
    method pred (line 47) | pred(node) {
    method succ (line 51) | succ(node) {
    method addEdge (line 55) | addEdge(u, v) {
    method removeEdge (line 64) | removeEdge(u, v) {
    method nodes (line 73) | nodes() {
    method serialize (line 77) | serialize() {
  function nodeToString (line 98) | function nodeToString(nd) {
  function Graph (line 104) | function Graph() {
  function getEnclosingFile (line 202) | function getEnclosingFile (nd) {
  class FlowGraph (line 215) | class FlowGraph extends Graph {
    method constructor (line 216) | constructor() {
    method addEdge (line 221) | addEdge(from, to, annote) {
    method _updateFileToNodes (line 227) | _updateFileToNodes(fgNode) {
    method removeNodesInFile (line 236) | removeNodesInFile(fileName) {

FILE: src/input-2.js
  function aap (line 1) | function aap() {
  function noot (line 5) | function noot() {
  function wim (line 10) | function wim() {
  function zus (line 14) | function zus(x, y) {
  function teun (line 20) | function teun() {
  function jet (line 24) | function jet(func) {

FILE: src/linkedList.js
  class ListNode (line 2) | class ListNode {
    method constructor (line 3) | constructor(ele) {
    method next (line 8) | set next(value) {
    method next (line 12) | get next() {
    method element (line 16) | get element() {
  class LinkedList (line 21) | class LinkedList {
    method constructor (line 22) | constructor() {
    method add (line 28) | add(ele) {
    method remove (line 36) | remove(ele) {
    method has (line 56) | has(ele) {
    method isEmpty (line 66) | isEmpty() {
    method size (line 70) | get size() {
  method [Symbol.iterator] (line 74) | [Symbol.iterator]() {

FILE: src/module.js
  function addFileToExports (line 98) | function addFileToExports(expFuncs, fname) {
  function addSrcToFile (line 107) | function addSrcToFile(impFuncs, fname, srcFname) {
  function rmFileFromExports (line 116) | function rmFileFromExports(expFuncs, fname) {
  function rmFileFromImports (line 121) | function rmFileFromImports(impFuncs, fname) {
  function addDefaultExport (line 145) | function addDefaultExport(expFuncs, fname, nd) {
  function mangle (line 162) | function mangle(funcName) {
  function unmangle (line 170) | function unmangle(funcName) {
  function addNamedExport (line 190) | function addNamedExport(expFuncs, fname, local, exportedName) {
  function addRedirectExport (line 213) | function addRedirectExport(expFuncs, fname, redirectFname) {
  function addDefaultImport (line 233) | function addDefaultImport(impFuncs, fname, srcFname, idNode) {
  function addNamedImport (line 258) | function addNamedImport(impFuncs, fname, srcFname, local, importedName) {
  function addEntireImport (line 293) | function addEntireImport(impFuncs, fname, srcFname) {
  function connectDefaultImport (line 314) | function connectDefaultImport(expFuncs, fg, srcFname, idNode) {
  function connectNamedImport (line 340) | function connectNamedImport(expFuncs, fg, srcFname, local, importedName) {
  function connectEntireImport (line 360) | function connectEntireImport(expFuncs, fg, srcFname) {
  function getRelativePath (line 385) | function getRelativePath(curPath, importPath) {
  function collectExportsImports (line 409) | function collectExportsImports(ast, expFuncs, impFuncs) {
  function connectImports (line 512) | function connectImports(fg, expFuncs, impFuncs) {

FILE: src/natives.js
  function addNativeFlowEdges (line 21) | function addNativeFlowEdges(flow_graph) {

FILE: src/olist.js
  function size (line 21) | function size(a) {
  function contains (line 34) | function contains(a, x) {
  function add (line 60) | function add(a, x) {
  function addAll (line 92) | function addAll(a, b) {
  function remove (line 129) | function remove(a, x) {
  function removeAll (line 156) | function removeAll(a, b) {
  function copy (line 189) | function copy(a) {
  function iter (line 196) | function iter(a, cb) {
  function map (line 205) | function map(a, f) {
  function some (line 216) | function some(a, f) {
  function all (line 231) | function all(a, f) {
  function fromArray (line 246) | function fromArray(ary) {
  function toArray (line 254) | function toArray(a) {

FILE: src/pessimistic.js
  function addOneShotEdges (line 22) | function addOneShotEdges(ast, fg) {
  function buildCallGraph (line 55) | function buildCallGraph(ast, noOneShot) {

FILE: src/requireJsGraph.js
  function makeRequireJsGraph (line 13) | function makeRequireJsGraph(ast) {
  function Dependency (line 56) | function Dependency(from, to) {

FILE: src/semioptimistic.js
  function addInterproceduralFlowEdges (line 27) | function addInterproceduralFlowEdges(ast, fg) {
  function buildCallGraph (line 97) | function buildCallGraph(ast) {

FILE: src/set.js
  function size (line 15) | function size(s) {
  function contains (line 26) | function contains(s, n) {
  function add (line 37) | function add(s, n) {
  function addAll (line 52) | function addAll(s1, s2) {
  function remove (line 80) | function remove(s, n) {
  function removeAll (line 94) | function removeAll(s1, s2) {
  function copy (line 115) | function copy(s) {
  function iter (line 123) | function iter(s, cb) {
  function map (line 132) | function map(s, f) {
  function fromArray (line 145) | function fromArray(ary) {
  function toArray (line 149) | function toArray(s) {

FILE: src/srcPreprocessor.js
  function applyPreps (line 31) | function applyPreps(src, fname, prepNames) {
  function stripFlowPrep (line 46) | function stripFlowPrep(src) {
  function trimHashbangPrep (line 60) | function trimHashbangPrep(src) {
  function typescriptPrep (line 86) | function typescriptPrep(fname, src) {

FILE: src/symtab.js
  function mangle (line 18) | function mangle(name) {
  function isMangled (line 22) | function isMangled(name) {
  function Symtab (line 26) | function Symtab(outer) {

FILE: src/tests.js
  function y (line 2) | function y() {

FILE: src/utils.js
  function collectFiles (line 7) | function collectFiles(dir, filelist) {

FILE: tests/basics/assignment.js
  function main (line 2) | function main() {

FILE: tests/callgraph.py
  function callgraph (line 10) | def callgraph(files):
  function callgraph_formatted (line 20) | def callgraph_formatted(files, keep='', natives=True):
  function format_func (line 58) | def format_func(out):
  function format_native (line 79) | def format_native(out):
  function format_output (line 98) | def format_output(out):

FILE: tests/classes/anonymous-class.js
  method constructor (line 2) | constructor () {

FILE: tests/classes/basic-class.js
  function Apple (line 1) | function Apple () {

FILE: tests/classes/basic-class2.js
  class Apple (line 1) | class Apple {
    method grow (line 2) | grow () {

FILE: tests/classes/class-expression1.js
  method constructor (line 2) | constructor() {

FILE: tests/classes/class-expression2.js
  method constructor (line 2) | constructor() {

FILE: tests/classes/class.js
  class Rectangle (line 1) | class Rectangle {
    method constructor (line 2) | constructor(height, width) {
    method area (line 7) | get area() {
    method calcArea (line 11) | calcArea() {

FILE: tests/classes/export-class-expression1.js
  method constructor (line 2) | constructor() {

FILE: tests/classes/export-class-expression2.js
  method constructor (line 2) | constructor() {

FILE: tests/classes/outer-fn.js
  function f2 (line 1) | function f2() {
  class A (line 5) | class A {
    method f (line 6) | f() {

FILE: tests/es6/array-pattern.js
  function main (line 5) | function main () {

FILE: tests/es6/array-pattern2.js
  function main (line 5) | function main () {

FILE: tests/es6/array-pattern3.js
  function main (line 5) | function main () {

FILE: tests/es6/array-pattern4.js
  function main (line 5) | function main () {

FILE: tests/es6/binding-pattern-global.js
  function main (line 3) | function main () {

FILE: tests/es6/destructured-parameter.js
  function main (line 6) | function main () {

FILE: tests/es6/destructured-parameter2.js
  function main (line 8) | function main () {

FILE: tests/es6/destructured-parameter3.js
  function main (line 8) | function main () {

FILE: tests/es6/lib.js
  function square (line 2) | function square(x) {
  function diag (line 5) | function diag(x, y) {

FILE: tests/es6/object-pattern.js
  function main (line 5) | function main () {

FILE: tests/es6/object-pattern2.js
  function main (line 5) | function main () {

FILE: tests/es6/object-pattern3.js
  function main (line 5) | function main () {

FILE: tests/import-export/es6/es6-cyclic-dependencies1.js
  function double (line 2) | function double(x) {

FILE: tests/import-export/es6/es6-export-fns.js
  function square (line 2) | function square(x) {
  function diag (line 5) | function diag(x, y) {

FILE: tests/import-export/es6/es6-export-hasOwnProperty.js
  function hasOwnProperty (line 1) | function hasOwnProperty(obj, prop) {

FILE: tests/import-export/es6/es6-export-mixed.js
  function each (line 4) | function each() {

FILE: tests/import-export/es6/redirect/auth.js
  function login (line 1) | function login(x) {
  function logout (line 5) | function logout(x, y) {

FILE: tests/import-export/es6/redirect/project.js
  function addProject (line 1) | function addProject() {
  function update (line 5) | function update() {

FILE: tests/import-export/es6/redirect/search.js
  function executeSearch (line 1) | function executeSearch(x, y, z) {

FILE: tests/jest/graph.test.js
  function make_pp (line 259) | function make_pp(s) {
  function make_pp (line 290) | function make_pp(s) {

FILE: tests/limits/history.js
  function main (line 4) | function main () {

FILE: tests/limits/overload.js
  function f (line 1) | function f() {
  function f (line 7) | function f(x) {

FILE: tests/process.py
  function get_output (line 17) | def get_output(test_file):
  function precision_recall (line 30) | def precision_recall(test_file, expected_output):

FILE: tests/required_files.py
  function match_to_path (line 10) | def match_to_path(match):
  function get_requires (line 17) | def get_requires(path):
  function collect_requires (line 43) | def collect_requires(path):

FILE: tests/test.py
  function find_truth_file (line 33) | def find_truth_file(test_file):

FILE: tests/typescript/simple.ts
  function greeter (line 1) | function greeter(person: string) {

FILE: tests/unexpected/stringiterator.js
  class StringIterator (line 3) | class StringIterator {
    method constructor (line 5) | constructor(string) {
    method next (line 14) | next() {
    method '@@iterator' (line 52) | '@@iterator'() {
  function createIterResultObject (line 57) | function createIterResultObject(value, done) {

FILE: tests/unhandled/classes/class-compiled.js
  function defineProperties (line 3) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _classCallCheck (line 5) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function Rectangle (line 8) | function Rectangle(height, width) {

FILE: tests/unhandled/classes/class-compiled2.js
  function defineProperties (line 3) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _classCallCheck (line 5) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function Rectangle (line 8) | function Rectangle(height, width) {

FILE: tests/unhandled/classes/class-getter.js
  class Rectangle (line 1) | class Rectangle {
    method constructor (line 2) | constructor(height, width) {
    method area (line 7) | get area() {
    method calcArea (line 11) | calcArea() {

FILE: tests/unhandled/limits/history.js
  function main (line 4) | function main () {

FILE: tests/unhandled/limits/overload.js
  function f (line 1) | function f() {
  function f (line 7) | function f(x) {
Condensed preview — 184 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,223K chars).
[
  {
    "path": ".eslintrc",
    "chars": 244,
    "preview": "{\n  \"env\": {\n    \"es6\": true,\n    \"node\": true,\n  },\n  \"rules\": {\n    \"no-console\": \"off\",\n    \"no-trailing-spaces\": \"er"
  },
  {
    "path": ".gitignore",
    "chars": 103,
    "preview": "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",
    "chars": 133,
    "preview": "language: node_js\nsudo: false\nnode_js:\n  - \"node\"\nbefore_install:\n  - pyenv global 3.6\ninstall:\n  - npm install\nscript:\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2475,
    "preview": "\n# How to contribute\n\nWelcome! We are super happy that you intend to contribute to the javascript-call-graph! This is a "
  },
  {
    "path": "LICENSE",
    "chars": 14199,
    "preview": "Eclipse Public License - v 2.0\n\n    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n    PUBLIC LICE"
  },
  {
    "path": "README.md",
    "chars": 8194,
    "preview": "# Field-based Call Graph Construction for JavaScript #\n\n\n[![Build Status](https://travis-ci.org/Persper/js-callgraph.svg"
  },
  {
    "path": "index.js",
    "chars": 662,
    "preview": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundatio"
  },
  {
    "path": "input-scripts/coolclock/coolclock.js",
    "chars": 11114,
    "preview": "/**\n * CoolClock 2.1.4\n * Copyright 2010, Simon Baird\n * Released under the BSD License.\n *\n * Display an analog clock u"
  },
  {
    "path": "input-scripts/coolclock/excanvas.js",
    "chars": 23822,
    "preview": "// Copyright 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "input-scripts/coolclock/moreskins.js",
    "chars": 13442,
    "preview": "CoolClock.config.skins = {\n\n\tswissRail: {\n\t\touterBorder:      { lineWidth: 2, radius: 95, color: \"black\", alpha: 1 },\n\t\t"
  },
  {
    "path": "input-scripts/flotr/flotr-0.2.0-alpha.js",
    "chars": 51223,
    "preview": "//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.\nvar Flotr={version:\"0.2.0-alph"
  },
  {
    "path": "input-scripts/flotr/flotr.debug-0.2.0-alpha.js",
    "chars": 103474,
    "preview": "//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.\n/* $Id: flotr.js 82 2009-01-12"
  },
  {
    "path": "input-scripts/flotr/lib/base64.js",
    "chars": 2977,
    "preview": "/* 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"
  },
  {
    "path": "input-scripts/flotr/lib/canvas2image.js",
    "chars": 6715,
    "preview": "/*\r\n * Canvas2Image v0.1\r\n * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com\r\n * MIT License [http://www.opensource."
  },
  {
    "path": "input-scripts/flotr/lib/canvastext.js",
    "chars": 21929,
    "preview": "/**\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 h"
  },
  {
    "path": "input-scripts/flotr/lib/excanvas.js",
    "chars": 26246,
    "preview": "// Copyright 2006 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "input-scripts/flotr/lib/prototype-1.6.0.2.js",
    "chars": 130345,
    "preview": "/*  Prototype JavaScript framework, version 1.6.0.2\r\n *  (c) 2005-2008 Sam Stephenson\r\n *\r\n *  Prototype is freely distr"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.css",
    "chars": 11147,
    "preview": "/*!\n * FullCalendar v1.6.4 Stylesheet\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n\n\n.fc"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.js",
    "chars": 151629,
    "preview": "/*!\n * FullCalendar v1.6.4\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */\n\n/*\n * Use fullc"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/fullcalendar.print.css",
    "chars": 668,
    "preview": "/*!\n * FullCalendar v1.6.4 Print Stylesheet\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Shaw\n */"
  },
  {
    "path": "input-scripts/fullcalendar/fullcalendar/gcal.js",
    "chars": 2658,
    "preview": "/*!\n * FullCalendar v1.6.4 Google Calendar Plugin\n * Docs & License: http://arshaw.com/fullcalendar/\n * (c) 2013 Adam Sh"
  },
  {
    "path": "input-scripts/fullcalendar/lib/jquery-2.1.0.js",
    "chars": 244963,
    "preview": "/*!\n * jQuery JavaScript Library v2.1.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Cop"
  },
  {
    "path": "input-scripts/simple-scripts/function_function.js",
    "chars": 1180,
    "preview": "var _createClass = function () {\n    function defineProperties(target, props) {\n        for (var i = 0; i < props.length"
  },
  {
    "path": "input-scripts/simple-scripts/functioncall-arithmetic.js",
    "chars": 158,
    "preview": "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 "
  },
  {
    "path": "input-scripts/simple-scripts/jQuery.js",
    "chars": 751,
    "preview": "(function() {\n function jQuery(n) {\n  var res = Object.create(jQuery.fn);\n  var elts = document.getElementsByTagName(n);"
  },
  {
    "path": "input-scripts/simple-scripts/or_function.js",
    "chars": 54,
    "preview": "b = false\n\nb = b || function () {\n  return true;\n}();\n"
  },
  {
    "path": "input-scripts/simple-scripts/use_before_definition.js",
    "chars": 128,
    "preview": "Object.defineProperty(exports, \"__esModule\", {\n  value: true\n});\n\nexports.default = add;\nfunction add(x, y) {\n  return x"
  },
  {
    "path": "js-callgraph.js",
    "chars": 2872,
    "preview": "#!/usr/bin/env node\n\n/*******************************************************************************\n * Copyright (c) 2"
  },
  {
    "path": "package.json",
    "chars": 1277,
    "preview": "{\n  \"name\": \"@persper/js-callgraph\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Builds static call graph for Javascript wit"
  },
  {
    "path": "saveSvgAsPng.js",
    "chars": 14564,
    "preview": "(function() {\n  const out$ = typeof exports != 'undefined' && exports || typeof define != 'undefined' && {} || this || w"
  },
  {
    "path": "scripts/install-hooks",
    "chars": 210,
    "preview": "#!/usr/bin/env bash\n\nGIT_DIR=$(git rev-parse --git-dir)\n\necho \"Installing hooks...\"\n# this command creates symlink to ou"
  },
  {
    "path": "scripts/pre-commit",
    "chars": 221,
    "preview": "#!/usr/bin/env bash\n\nREPO_DIR=$(git rev-parse --show-toplevel)\n\necho \"Running pre-commit hook\"\n\nnpm test\n\n# $? stores ex"
  },
  {
    "path": "src/astutil.js",
    "chars": 16753,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/bindings.js",
    "chars": 8779,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/bitset.js",
    "chars": 5906,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/callbackCounter.js",
    "chars": 3110,
    "preview": "if (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function(require, exports) {"
  },
  {
    "path": "src/callgraph.js",
    "chars": 2362,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/dftc.js",
    "chars": 5630,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/diagnostics.js",
    "chars": 1143,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/flowgraph.js",
    "chars": 14877,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/graph.js",
    "chars": 7326,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/harness.js",
    "chars": 42352,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/input-2.js",
    "chars": 287,
    "preview": "function aap() {\n    noot();\n}\n\nfunction noot() {\n    var mies = wim;\n    mies();\n}\n\nfunction wim() {\n    var output = z"
  },
  {
    "path": "src/linkedList.js",
    "chars": 2024,
    "preview": "\nclass ListNode {\n    constructor(ele) {\n        this._ele = ele;\n        this._next = null;\n    }\n\n    set next(value) "
  },
  {
    "path": "src/module.js",
    "chars": 18282,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/natives.js",
    "chars": 1339,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/numset.js",
    "chars": 886,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/olist.js",
    "chars": 6769,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/pessimistic.js",
    "chars": 2714,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/requireJsGraph.js",
    "chars": 2786,
    "preview": "if (typeof define !== 'function') {\n    var define = require('amdefine')(module);\n}\n\ndefine(function(require, exports) {"
  },
  {
    "path": "src/runner.js",
    "chars": 8567,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/semioptimistic.js",
    "chars": 4320,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/set.js",
    "chars": 3730,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/srcPreprocessor.js",
    "chars": 3056,
    "preview": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundatio"
  },
  {
    "path": "src/symtab.js",
    "chars": 1944,
    "preview": "/*******************************************************************************\n * Copyright (c) 2013 Max Schaefer\n * C"
  },
  {
    "path": "src/tests.js",
    "chars": 57,
    "preview": "// function go(x) { x = 3; }\nfunction y() {\nvar x = 1;\n}\n"
  },
  {
    "path": "src/underscore.js",
    "chars": 47994,
    "preview": "//     Underscore.js 1.5.2\n//     http://underscorejs.org\n//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Invest"
  },
  {
    "path": "src/utils.js",
    "chars": 587,
    "preview": "const fs = require('fs');\nconst path = require('path');\n\n/**\n * Collect all the files in the given directory, recursivel"
  },
  {
    "path": "tests/README.md",
    "chars": 1721,
    "preview": "# Test Documentation\n\n## Overview\n\nOur tests consist of two parts: unit tests run by jest and integration tests run by a"
  },
  {
    "path": "tests/basics/arrow.js",
    "chars": 48,
    "preview": "arrowFunc = x => { return x; };\n\narrowFunc(10);\n"
  },
  {
    "path": "tests/basics/arrow.truth",
    "chars": 37,
    "preview": "arrow.js:global:3 -> arrow.js:anon:1\n"
  },
  {
    "path": "tests/basics/assignment.js",
    "chars": 200,
    "preview": "// This file tests assigning a function object to an existing local variable\nfunction main() {\n\tlet a = 1;\n\tlet b = func"
  },
  {
    "path": "tests/basics/assignment.truth",
    "chars": 126,
    "preview": "assignment.js:funcB:5 -> Native\nassignment.js:main:8 -> assignment.js:funcB:4\nassignment.js:global:11 -> assignment.js:m"
  },
  {
    "path": "tests/basics/global-as-prop.js",
    "chars": 516,
    "preview": "/*\nSince we introduced `GlobVertex`, this problem has been fixed and we can now distinguish\nbetween the two function cal"
  },
  {
    "path": "tests/basics/global-as-prop.truth",
    "chars": 111,
    "preview": "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",
    "chars": 179,
    "preview": "// Same code with global-as-prop.js, wrapped in a function\n(function () {\n  let a = function (x) { return x; };\n  let b "
  },
  {
    "path": "tests/basics/local-is-fine.truth",
    "chars": 152,
    "preview": "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"
  },
  {
    "path": "tests/basics/method-def.js",
    "chars": 179,
    "preview": "var obj = {\n    randomMethod1: function () {\n        return 42;\n    },\n    'randomMethod2': function () {\n        return"
  },
  {
    "path": "tests/basics/method-def.truth",
    "chars": 114,
    "preview": "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",
    "chars": 2995,
    "preview": "# Summary: Methods for collecting callgraph output\n#          and formatting it into truth file output\n\nimport subproces"
  },
  {
    "path": "tests/classes/anonymous-class.js",
    "chars": 64,
    "preview": "export default class {\n  constructor () {\n    this.p = 0;\n  }\n}\n"
  },
  {
    "path": "tests/classes/basic-class.js",
    "chars": 91,
    "preview": "function Apple () {\n  this.grow = function () {\n\n  }\n}\n\napple = new Apple();\napple.grow();\n"
  },
  {
    "path": "tests/classes/basic-class.truth",
    "chars": 99,
    "preview": "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",
    "chars": 69,
    "preview": "class Apple {\n  grow () {\n\n  }\n}\n\napple = new Apple();\napple.grow();\n"
  },
  {
    "path": "tests/classes/basic-class2.truth",
    "chars": 51,
    "preview": "basic-class2.js:global:8 -> basic-class2.js:grow:2\n"
  },
  {
    "path": "tests/classes/class-expression1.js",
    "chars": 69,
    "preview": "let x = class Apple {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nx();\n"
  },
  {
    "path": "tests/classes/class-expression1.truth",
    "chars": 68,
    "preview": "class-expression1.js:global:7 -> class-expression1.js:constructor:2\n"
  },
  {
    "path": "tests/classes/class-expression2.js",
    "chars": 63,
    "preview": "let x = class {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nx();\n"
  },
  {
    "path": "tests/classes/class-expression2.truth",
    "chars": 68,
    "preview": "class-expression2.js:global:7 -> class-expression2.js:constructor:2\n"
  },
  {
    "path": "tests/classes/class.js",
    "chars": 304,
    "preview": "class Rectangle {\n  constructor(height, width) {\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n  get"
  },
  {
    "path": "tests/classes/class.truth",
    "chars": 157,
    "preview": "class.js:area:8 -> class.js:calcArea:11\nclass.js:global:16 -> class.js:constructor:2\nclass.js:global:18 -> Native\nclass."
  },
  {
    "path": "tests/classes/export-class-expression1.js",
    "chars": 82,
    "preview": "let x = class Apple {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nexport default x;\n"
  },
  {
    "path": "tests/classes/export-class-expression2.js",
    "chars": 76,
    "preview": "let x = class {\n  constructor() {\n    this.p = 10;\n  }\n}\n\nexport default x;\n"
  },
  {
    "path": "tests/classes/import-anonymous-class.js",
    "chars": 51,
    "preview": "import a from 'anonymous-class';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-anonymous-class.truth",
    "chars": 71,
    "preview": "import-anonymous-class.js:global:3 -> anonymous-class.js:constructor:2\n"
  },
  {
    "path": "tests/classes/import-class-expression1.js",
    "chars": 60,
    "preview": "import a from 'export-class-expression1';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-class-expression1.truth",
    "chars": 82,
    "preview": "import-class-expression1.js:global:3 -> export-class-expression1.js:constructor:2\n"
  },
  {
    "path": "tests/classes/import-class-expression2.js",
    "chars": 60,
    "preview": "import a from 'export-class-expression2';\n\nvar x = new a();\n"
  },
  {
    "path": "tests/classes/import-class-expression2.truth",
    "chars": 82,
    "preview": "import-class-expression2.js:global:3 -> export-class-expression2.js:constructor:2\n"
  },
  {
    "path": "tests/classes/outer-fn.js",
    "chars": 73,
    "preview": "function f2() {\n    return 5\n}\n\nclass A {\n    f() {\n        f2()\n    }\n}\n"
  },
  {
    "path": "tests/classes/outer-fn.truth",
    "chars": 36,
    "preview": "outer-fn.js:f:7 -> outer-fn.js:f2:1\n"
  },
  {
    "path": "tests/creating-vue-compiled.txt",
    "chars": 420,
    "preview": "The steps to making the vue-compiled directory were:\n\n1. copy the entire vue directory to a fold called vue-compiled\n2. "
  },
  {
    "path": "tests/es6/array-pattern.js",
    "chars": 239,
    "preview": "/*\nArray destructuing: basic variable assignment\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Opera"
  },
  {
    "path": "tests/es6/array-pattern.truth",
    "chars": 105,
    "preview": "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",
    "chars": 254,
    "preview": "/*\nArray destructuing: assignment separate from declaration\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe"
  },
  {
    "path": "tests/es6/array-pattern2.truth",
    "chars": 109,
    "preview": "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",
    "chars": 275,
    "preview": "/*\nArray destructuing: parsing an array returned from a function\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript"
  },
  {
    "path": "tests/es6/array-pattern3.truth",
    "chars": 162,
    "preview": "array-pattern3.js:main:7 -> array-pattern3.js:anon:6\narray-pattern3.js:main:8 -> array-pattern3.js:anon:6\narray-pattern3"
  },
  {
    "path": "tests/es6/array-pattern4.js",
    "chars": 269,
    "preview": "/*\nArray destructuing: ignoring some return values\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Ope"
  },
  {
    "path": "tests/es6/array-pattern4.truth",
    "chars": 162,
    "preview": "array-pattern4.js:main:7 -> array-pattern4.js:anon:6\narray-pattern4.js:main:8 -> array-pattern4.js:anon:6\narray-pattern4"
  },
  {
    "path": "tests/es6/binding-pattern-global.js",
    "chars": 569,
    "preview": "let v = () => { return 1; };\n\nfunction main () {\n\tv();\n\t[v] = [null];\n}\n\nmain();\n/*\nThis test illustrates how the curren"
  },
  {
    "path": "tests/es6/binding-pattern-global.truth",
    "chars": 140,
    "preview": "binding-pattern-global.js:main:4 -> binding-pattern-global.js:anon:1\nbinding-pattern-global.js:global:8 -> binding-patte"
  },
  {
    "path": "tests/es6/destructured-parameter.js",
    "chars": 346,
    "preview": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/"
  },
  {
    "path": "tests/es6/destructured-parameter.truth",
    "chars": 273,
    "preview": "destructured-parameter.js:f:8 -> destructured-parameter.js:anon:10\ndestructured-parameter.js:f:8 -> destructured-paramet"
  },
  {
    "path": "tests/es6/destructured-parameter2.js",
    "chars": 1299,
    "preview": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/"
  },
  {
    "path": "tests/es6/destructured-parameter2.truth",
    "chars": 213,
    "preview": "destructured-parameter2.js:f:10 -> destructured-parameter2.js:anon:12\ndestructured-parameter2.js:main:13 -> destructured"
  },
  {
    "path": "tests/es6/destructured-parameter3.js",
    "chars": 1310,
    "preview": "/*\nDestructured parameter\nSee the last code example in the following link:\nhttps://developer.mozilla.org/en-US/docs/Web/"
  },
  {
    "path": "tests/es6/destructured-parameter3.truth",
    "chars": 213,
    "preview": "destructured-parameter3.js:f:10 -> destructured-parameter3.js:anon:12\ndestructured-parameter3.js:main:13 -> destructured"
  },
  {
    "path": "tests/es6/lib.js",
    "chars": 150,
    "preview": "export const sqrt = Math.sqrt;\nexport function square(x) {\n    return x * x;\n}\nexport function diag(x, y) {\n    return s"
  },
  {
    "path": "tests/es6/main.js",
    "chars": 98,
    "preview": "import { square, diag } from 'lib';\nconsole.log(square(11)); // 121\nconsole.log(diag(4, 3)); // 5\n"
  },
  {
    "path": "tests/es6/main.truth",
    "chars": 124,
    "preview": "main.js:global:2 -> Native\nmain.js:global:2 -> lib.js:square:2\nmain.js:global:3 -> Native\nmain.js:global:3 -> lib.js:dia"
  },
  {
    "path": "tests/es6/object-pattern.js",
    "chars": 237,
    "preview": "/*\nObject destructuing: basic assignment\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Des"
  },
  {
    "path": "tests/es6/object-pattern.truth",
    "chars": 109,
    "preview": "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",
    "chars": 251,
    "preview": "/*\nObject destructuing: assign without declaration\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Ope"
  },
  {
    "path": "tests/es6/object-pattern2.truth",
    "chars": 113,
    "preview": "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",
    "chars": 259,
    "preview": "/*\nObject destructuing: assigning to new variable names\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc"
  },
  {
    "path": "tests/es6/object-pattern3.truth",
    "chars": 113,
    "preview": "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",
    "chars": 2916,
    "preview": "create-component.js.o:anon:3 -> Native\ncreate-component.js.o:anon:9 -> Native\ncreate-component.js.o:anon:11 -> create-co"
  },
  {
    "path": "tests/ground_truths/create-element.txt",
    "chars": 3191,
    "preview": "create-element.js.o:anon:3 -> Native\ncreate-element.js.o:anon:9 -> Native\ncreate-element.js.o:anon:11 -> create-element."
  },
  {
    "path": "tests/ground_truths/ground-truth.txt",
    "chars": 1196,
    "preview": "Template:\n<filename>:<enclosing_function_name | undefined | global>:<line_number> -> <filename>:<called_function_name | "
  },
  {
    "path": "tests/ground_truths/patch.txt",
    "chars": 1696,
    "preview": "patch.js.o:3 -> NativeVertex\npatch.js.o:9 -> NativeVertex\npatch.js.o:11 -> patch.js.o:_interopRequireDefault:29\npatch.js"
  },
  {
    "path": "tests/ground_truths/vnode.txt",
    "chars": 498,
    "preview": "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:an"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-module.js",
    "chars": 202,
    "preview": "// This module directly assigns the constructor function for User to module.exports\nif (typeof define !== 'function') {\n"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-require.js",
    "chars": 164,
    "preview": "// This file tests directly assigning a constructor function to module.exports\nlet arrow = require('./arrow-func-no-bloc"
  },
  {
    "path": "tests/import-export/define/arrow-func-no-block-statement-require.truth",
    "chars": 100,
    "preview": "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",
    "chars": 286,
    "preview": "// This module directly assigns the constructor function for User to module.exports\nif (typeof define !== 'function') {\n"
  },
  {
    "path": "tests/import-export/define/define-require.js",
    "chars": 229,
    "preview": "// This file tests directly assigning a constructor function to module.exports\nlet user = require('./define-module');\n\nl"
  },
  {
    "path": "tests/import-export/define/define-require.truth",
    "chars": 128,
    "preview": "define-require.js:global:2 -> Native\ndefine-require.js:global:4 -> define-module.js:anon:7\ndefine-require.js:global:5 ->"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies1.js",
    "chars": 110,
    "preview": "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",
    "chars": 75,
    "preview": "es6-cyclic-dependencies1.js:global:5 -> es6-cyclic-dependencies2.js:anon:3\n"
  },
  {
    "path": "tests/import-export/es6/es6-cyclic-dependencies2.js",
    "chars": 114,
    "preview": "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",
    "chars": 77,
    "preview": "es6-cyclic-dependencies2.js:global:2 -> es6-cyclic-dependencies1.js:double:2\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-default.js",
    "chars": 42,
    "preview": "export default function () { return 4; };\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-fns.js",
    "chars": 150,
    "preview": "export const sqrt = Math.sqrt;\nexport function square(x) {\n    return x * x;\n}\nexport function diag(x, y) {\n    return s"
  },
  {
    "path": "tests/import-export/es6/es6-export-hasOwnProperty.js",
    "chars": 90,
    "preview": "function hasOwnProperty(obj, prop) {\n    return prop in obj;\n}\nexport { hasOwnProperty };\n"
  },
  {
    "path": "tests/import-export/es6/es6-export-mixed.js",
    "chars": 114,
    "preview": "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",
    "chars": 51,
    "preview": "import myFunc from 'es6-export-default';\nmyFunc();\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-default.truth",
    "chars": 63,
    "preview": "es6-import-default.js:global:2 -> es6-export-default.js:anon:1\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-entire.js",
    "chars": 109,
    "preview": "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",
    "chars": 198,
    "preview": "es6-import-entire.js:global:2 -> Native\nes6-import-entire.js:global:2 -> es6-export-fns.js:square:2\nes6-import-entire.js"
  },
  {
    "path": "tests/import-export/es6/es6-import-hasOwnProperty.js",
    "chars": 113,
    "preview": "import { hasOwnProperty } from 'es6-export-hasOwnProperty';\nconsole.log(hasOwnProperty({'prop': true}, 'prop'));\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-hasOwnProperty.truth",
    "chars": 87,
    "preview": "es6-import-hasOwnProperty.js:global:2 -> es6-export-hasOwnProperty.js:hasOwnProperty:1\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-mixed.js",
    "chars": 58,
    "preview": "import _, { each } from 'es6-export-mixed';\n\n_();\neach();\n"
  },
  {
    "path": "tests/import-export/es6/es6-import-mixed.truth",
    "chars": 118,
    "preview": "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",
    "chars": 109,
    "preview": "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",
    "chars": 194,
    "preview": "es6-import-named.js:global:2 -> Native\nes6-import-named.js:global:2 -> es6-export-fns.js:square:2\nes6-import-named.js:gl"
  },
  {
    "path": "tests/import-export/es6/es6-import-redirect.js",
    "chars": 216,
    "preview": "import {login, logout, addProject, updateProject, executeSearch} from 'redirect/index';\n// import {updateProject} from '"
  },
  {
    "path": "tests/import-export/es6/es6-import-redirect.truth",
    "chars": 278,
    "preview": "es6-import-redirect.js:global:3 -> auth.js:login:1\nes6-import-redirect.js:global:4 -> auth.js:logout:5\nes6-import-redire"
  },
  {
    "path": "tests/import-export/es6/redirect/auth.js",
    "chars": 103,
    "preview": "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",
    "chars": 131,
    "preview": "export {login, logout} from './auth';\nexport {addProject, updateProject} from './project';\nexport {executeSearch} from '"
  },
  {
    "path": "tests/import-export/es6/redirect/project.js",
    "chars": 139,
    "preview": "function addProject() {\n  return 'whooplah';\n}\n\nfunction update() {\n  return 'dooplah';\n}\n\nexport { addProject, update a"
  },
  {
    "path": "tests/import-export/es6/redirect/search.js",
    "chars": 81,
    "preview": "function executeSearch(x, y, z) {\n  return x * y * z;\n}\nexport { executeSearch }\n"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-module.js",
    "chars": 186,
    "preview": "// This module directly assigns the constructor function for User to module.exports\nlet User = function(name, email) {\n\t"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-module2.js",
    "chars": 113,
    "preview": "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",
    "chars": 237,
    "preview": "// This file tests directly assigning a constructor function to module.exports\nlet user = require('./module-exports-modu"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require.truth",
    "chars": 160,
    "preview": "module-exports-require.js:global:2 -> Native\nmodule-exports-require.js:global:4 -> module-exports-module.js:anon:2\nmodul"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require2.js",
    "chars": 169,
    "preview": "// This file tests the most common usage of exports/require\nlet m1 = require('./module-exports-module2');\nconsole.log(\"A"
  },
  {
    "path": "tests/import-export/module.exports/module-exports-require2.truth",
    "chars": 164,
    "preview": "module-exports-require2.js:global:2 -> Native\nmodule-exports-require2.js:global:3 -> Native\nmodule-exports-require2.js:g"
  },
  {
    "path": "tests/jest/graph.test.js",
    "chars": 9078,
    "preview": "/*******************************************************************************\n * Copyright (c) 2018 Persper Foundatio"
  },
  {
    "path": "tests/jest/linkedList.test.js",
    "chars": 754,
    "preview": "\nconst { LinkedList } = require('../../src/linkedList');\n\ntest('test LinkedList', () => {\n    let ll = new LinkedList();"
  },
  {
    "path": "tests/limits/history.js",
    "chars": 438,
    "preview": "// This file illustrates one of the limitations of the call graph algorithm\n// Only func2 is called in main function,\n//"
  },
  {
    "path": "tests/limits/history.truth",
    "chars": 181,
    "preview": "history.js:func1:5 -> Native\nhistory.js:func1:7 -> Native\nhistory.js:main:9 -> history.js:func2:7\nhistory.js:main:10 -> "
  },
  {
    "path": "tests/limits/overload.js",
    "chars": 73,
    "preview": "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",
    "chars": 81,
    "preview": "overload.js:global:5 -> overload.js:f:1\noverload.js:global:11 -> overload.js:f:7\n"
  },
  {
    "path": "tests/process.py",
    "chars": 1944,
    "preview": "#!/usr/bin/python3\n\n# Author: Alex Stennet\n# Description: Provides a testing framework for the call graph genereation\n#\n"
  },
  {
    "path": "tests/required_files.py",
    "chars": 1587,
    "preview": "import re\nfrom pathlib import Path\n\nreg1 = re.compile(\"require\\\\(\\'(.*)\\'\\\\)\")\nreg2 = re.compile(\"import .* from \\'(.*)\\"
  },
  {
    "path": "tests/test.py",
    "chars": 1791,
    "preview": "#!/usr/bin/python3\n\nimport os, sys, glob, time\nfrom os.path import isfile, join, dirname, isdir, basename\nfrom process i"
  },
  {
    "path": "tests/typescript/simple.truth",
    "chars": 42,
    "preview": "simple.ts:global:7 -> simple.ts:greeter:1\n"
  },
  {
    "path": "tests/typescript/simple.ts",
    "chars": 135,
    "preview": "function greeter(person: string) {\n    return \"Hello, \" + person;\n}\n\nlet user = \"Jane User\";\n\ndocument.body.innerHTML = "
  },
  {
    "path": "tests/unexpected/stringiterator.js",
    "chars": 1558,
    "preview": "// this code is extracted from Libraries/vendor/core/toIterator.js of the following commit\n// https://github.com/faceboo"
  },
  {
    "path": "tests/unexpected/stringiterator.truth",
    "chars": 219,
    "preview": "stringiterator.js:next:48 -> stringiterator.js:createIterResultObject:57\nstringiterator.js:next:29 -> stringiterator.js:"
  },
  {
    "path": "tests/unhandled/classes/class-compiled.js",
    "chars": 1238,
    "preview": "\"use strict\";\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.len"
  },
  {
    "path": "tests/unhandled/classes/class-compiled.truth",
    "chars": 677,
    "preview": "class-compiled.js:global:3 -> class-compiled.js:anon:3\nclass-compiled.js:defineProperties:3 -> Native\nclass-compiled.js:"
  },
  {
    "path": "tests/unhandled/classes/class-compiled2.js",
    "chars": 1244,
    "preview": "\"use strict\";\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.len"
  },
  {
    "path": "tests/unhandled/classes/class-compiled2.truth",
    "chars": 703,
    "preview": "class-compiled2.js:global:3 -> class-compiled2.js:anon:3\nclass-compiled2.js:defineProperties:3 -> Native\nclass-compiled2"
  },
  {
    "path": "tests/unhandled/classes/class-getter.js",
    "chars": 298,
    "preview": "class Rectangle {\n  constructor(height, width) {\n    this.height = height;\n    this.width = width;\n  }\n  // Getter\n  get"
  },
  {
    "path": "tests/unhandled/classes/class-getter.truth",
    "chars": 201,
    "preview": "class-getter.js:area:8 -> class-getter.js:calcArea:11\nclass-getter.js:global:16 -> class-getter.js:constructor:2\nclass-g"
  },
  {
    "path": "tests/unhandled/limits/history.js",
    "chars": 438,
    "preview": "// This file illustrates one of the limitations of the call graph algorithm\n// Only func2 is called in main function,\n//"
  },
  {
    "path": "tests/unhandled/limits/history.truth",
    "chars": 181,
    "preview": "history.js:func1:5 -> Native\nhistory.js:func1:7 -> Native\nhistory.js:main:9 -> history.js:func2:7\nhistory.js:main:10 -> "
  },
  {
    "path": "tests/unhandled/limits/overload.js",
    "chars": 73,
    "preview": "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",
    "chars": 81,
    "preview": "overload.js:global:5 -> overload.js:f:1\noverload.js:global:11 -> overload.js:f:7\n"
  },
  {
    "path": "tests/vue/TodoList.truth",
    "chars": 95,
    "preview": "TodoList.vue:addTodo:62 -> example.vue:data:10\nTodoList.vue:addTodo:62 -> TodoList.vue:data:33\n"
  },
  {
    "path": "tests/vue/TodoList.vue",
    "chars": 1736,
    "preview": "<template>\n    <div>\n        <BaseInputText \n            v-model=\"newTodoText\"\n            placeholder=\"New todo\"\n      "
  },
  {
    "path": "tests/vue/example.vue",
    "chars": 237,
    "preview": "<template lang=\"pug\">\n.hello\n  h1 {{ msg }}\n</template>\n \n<script lang=\"js\">\nexport default {\n  name: 'Hello',\n \n  data "
  }
]

About this extraction

This page contains the full source code of the Persper/js-callgraph GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 184 files (1.1 MB), approximately 305.2k tokens, and a symbol index with 422 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!