[med-svn] [emperor] 01/01: packaging erroor fixed

Kerim Ölçer kerimlcr-guest at moszumanska.debian.org
Thu Mar 16 12:35:11 UTC 2017


This is an automated email from the git hooks/post-receive script.

kerimlcr-guest pushed a commit to branch master
in repository emperor.

commit 698b9e588023272fd50d50d0290c243a9d80cbea
Author: Kerim Ölçer <kerimlcr at gmail.com>
Date:   Thu Mar 16 15:33:52 2017 +0300

    packaging erroor fixed
---
 CONTRIBUTING.md                                    |   127 +
 debian/changelog                                   |     8 +-
 debian/control                                     |    49 +-
 debian/copyright                                   |    62 +-
 debian/doc-base                                    |     8 -
 debian/docs                                        |     2 -
 debian/files                                       |     4 +
 debian/make_emperor.1                              |   218 -
 debian/manpages                                    |     1 -
 debian/patches/fetch_examples_from_web.patch       |    19 -
 debian/patches/series                              |     1 -
 debian/rules                                       |    36 +-
 debian/source/options                              |     1 +
 debian/upstream/metadata                           |    12 -
 doc/Makefile                                       |   181 +
 doc/README.md                                      |    60 +
 doc/bootstrap/css/bootstrap-theme.min.css          |     6 +
 doc/bootstrap/css/bootstrap.min.css                |     6 +
 .../fonts/glyphicons-halflings-regular.eot         |   Bin 0 -> 20127 bytes
 .../fonts/glyphicons-halflings-regular.svg         |   288 +
 .../fonts/glyphicons-halflings-regular.ttf         |   Bin 0 -> 45404 bytes
 .../fonts/glyphicons-halflings-regular.woff        |   Bin 0 -> 23424 bytes
 .../fonts/glyphicons-halflings-regular.woff2       |   Bin 0 -> 18028 bytes
 doc/bootstrap/js/bootstrap.min.js                  |     7 +
 doc/bootstrap/js/jquery-2.2.3.min.js               |     4 +
 doc/files/files.zip                                |   Bin 0 -> 542041 bytes
 doc/installation_index.html                        |   202 -
 doc/jsdoc-config.json                              |    20 +
 doc/source/_static/copybutton.js                   |    60 +
 doc/source/_static/style.css                       |    38 +
 doc/source/_templates/autosummary/attribute.rst    |     9 +
 doc/source/_templates/autosummary/class.rst        |    27 +
 doc/source/_templates/autosummary/method.rst       |     9 +
 doc/source/_templates/layout.html                  |    26 +
 doc/source/conf.py                                 |   282 +
 doc/source/emperor_objects.rst                     |     4 +
 doc/source/formats.rst                             |    65 +
 doc/source/index.rst                               |    38 +
 doc/source/sphinxext/numpydoc/LICENSE.txt          |    94 +
 doc/source/sphinxext/numpydoc/README.rst           |    54 +
 doc/source/sphinxext/numpydoc/numpydoc/__init__.py |     3 +
 .../sphinxext/numpydoc/numpydoc/comment_eater.py   |   169 +
 .../numpydoc/numpydoc/compiler_unparse.py          |   865 +
 .../sphinxext/numpydoc/numpydoc/docscrape.py       |   525 +
 .../numpydoc/numpydoc/docscrape_sphinx.py          |   274 +
 doc/source/sphinxext/numpydoc/numpydoc/linkcode.py |    83 +
 doc/source/sphinxext/numpydoc/numpydoc/numpydoc.py |   187 +
 .../sphinxext/numpydoc/numpydoc/phantom_import.py  |   167 +
 .../sphinxext/numpydoc/numpydoc/plot_directive.py  |   642 +
 .../numpydoc/numpydoc/tests/test_docscrape.py      |   767 +
 .../numpydoc/numpydoc/tests/test_linkcode.py       |     5 +
 .../numpydoc/numpydoc/tests/test_phantom_import.py |    12 +
 .../numpydoc/numpydoc/tests/test_plot_directive.py |    11 +
 .../numpydoc/numpydoc/tests/test_traitsdoc.py      |    11 +
 .../sphinxext/numpydoc/numpydoc/traitsdoc.py       |   142 +
 emperor/_pandas.py                                 |   103 +
 emperor/core.py                                    |   332 +
 emperor/parse.py                                   |    43 +
 emperor/pycogent_backports/__init__.py             |    12 -
 emperor/pycogent_backports/procrustes.py           |   157 -
 emperor/support_files/README.md                    |     8 +
 emperor/support_files/css/colorPicker.css          |    31 -
 emperor/support_files/css/d3.parcoords.css         |    40 -
 emperor/support_files/css/emperor.css              |    62 +
 .../css/images/ui-bg_flat_0_aaaaaa_40x100.png      |   Bin 180 -> 0 bytes
 .../css/images/ui-bg_flat_75_ffffff_40x100.png     |   Bin 178 -> 0 bytes
 .../css/images/ui-bg_glass_55_fbf9ee_1x400.png     |   Bin 120 -> 0 bytes
 .../css/images/ui-bg_glass_65_ffffff_1x400.png     |   Bin 105 -> 0 bytes
 .../css/images/ui-bg_glass_75_dadada_1x400.png     |   Bin 111 -> 0 bytes
 .../css/images/ui-bg_glass_75_e6e6e6_1x400.png     |   Bin 110 -> 0 bytes
 .../css/images/ui-bg_glass_95_fef1ec_1x400.png     |   Bin 119 -> 0 bytes
 .../ui-bg_highlight-soft_75_cccccc_1x100.png       |   Bin 101 -> 0 bytes
 .../css/images/ui-icons_222222_256x240.png         |   Bin 4369 -> 0 bytes
 .../css/images/ui-icons_2e83ff_256x240.png         |   Bin 4369 -> 0 bytes
 .../css/images/ui-icons_454545_256x240.png         |   Bin 4369 -> 0 bytes
 .../css/images/ui-icons_888888_256x240.png         |   Bin 4369 -> 0 bytes
 .../css/images/ui-icons_cd0a0a_256x240.png         |   Bin 4369 -> 0 bytes
 .../support_files/css/jquery-ui-1.8.16.custom.css  |   568 -
 emperor/support_files/css/jquery-ui2.css           |   567 -
 emperor/support_files/css/spectrum.css             |   408 -
 emperor/support_files/emperor/css/emperor.css      |   284 -
 emperor/support_files/emperor/js/emperor.js        |  2430 --
 emperor/support_files/js/FileSaver.min.js          |     2 -
 emperor/support_files/js/THREEx.screenshot.js      |   130 -
 emperor/support_files/js/Three.js                  | 37637 -------------------
 emperor/support_files/js/abc-view-controller.js    |   187 +
 emperor/support_files/js/animate.js                |   276 +
 emperor/support_files/js/axes-controller.js        |   441 +
 emperor/support_files/js/color-editor.js           |   141 +
 emperor/support_files/js/color-view-controller.js  |   537 +
 emperor/support_files/js/controller.js             |   617 +
 emperor/support_files/js/d3.parcoords.js           |   568 -
 emperor/support_files/js/d3.v3.min.js              |     5 -
 emperor/support_files/js/draw.js                   |   174 +
 emperor/support_files/js/jquery-1.7.1.min.js       |     4 -
 .../js/jquery-ui-1.8.17.custom.min.js              |   356 -
 emperor/support_files/js/jquery.colorPicker.js     |   328 -
 emperor/support_files/js/js/AudioObject.js         |   172 -
 emperor/support_files/js/js/Car.js                 |   364 -
 emperor/support_files/js/js/DAT.GUI.min.js         |    53 -
 emperor/support_files/js/js/Detector.js            |    58 -
 emperor/support_files/js/js/ImprovedNoise.js       |    71 -
 emperor/support_files/js/js/PRNG.js                |    11 -
 .../support_files/js/js/RequestAnimationFrame.js   |    22 -
 emperor/support_files/js/js/ShaderExtras.js        |  1779 -
 emperor/support_files/js/js/ShaderSkin.js          |   752 -
 emperor/support_files/js/js/ShaderTerrain.js       |   306 -
 emperor/support_files/js/js/SimplexNoise.js        |   316 -
 emperor/support_files/js/js/Sparks.js              |   832 -
 emperor/support_files/js/js/Stats.js               |     8 -
 emperor/support_files/js/js/Tween.js               |    13 -
 emperor/support_files/js/js/ctm/CTMLoader.js       |   821 -
 emperor/support_files/js/js/ctm/CTMWorker.js       |    19 -
 emperor/support_files/js/js/ctm/ctm.js             |   626 -
 .../support_files/js/js/ctm/license/OpenCTM.txt    |    20 -
 .../support_files/js/js/ctm/license/js-openctm.txt |    19 -
 emperor/support_files/js/js/ctm/lzma.js            |   510 -
 .../js/js/postprocessing/BloomPass.js              |   100 -
 .../js/js/postprocessing/DotScreenPass.js          |    52 -
 .../js/js/postprocessing/EffectComposer.js         |   136 -
 .../support_files/js/js/postprocessing/FilmPass.js |    51 -
 .../support_files/js/js/postprocessing/MaskPass.js |    86 -
 .../js/js/postprocessing/RenderPass.js             |    51 -
 .../support_files/js/js/postprocessing/SavePass.js |    52 -
 .../js/js/postprocessing/ShaderPass.js             |    51 -
 .../js/js/postprocessing/TexturePass.js            |    37 -
 emperor/support_files/js/model.js                  |   380 +
 emperor/support_files/js/scale-editor.js           |   124 +
 emperor/support_files/js/scale-view-controller.js  |   278 +
 emperor/support_files/js/sceneplotview3d.js        |   659 +
 emperor/support_files/js/shape-controller.js       |   108 +
 emperor/support_files/js/shape-editor.js           |   106 +
 emperor/support_files/js/shapes.js                 |    55 +
 emperor/support_files/js/specifications.txt        |     1 -
 emperor/support_files/js/spectrum.js               |  1566 -
 emperor/support_files/js/trajectory.js             |   406 +
 emperor/support_files/js/util.js                   |   147 +
 emperor/support_files/js/view-controller.js        |   327 +
 emperor/support_files/js/view.js                   |   285 +
 emperor/support_files/js/visibility-controller.js  |    96 +
 .../support_files/templates/jupyter-template.html  |     3 +
 .../support_files/templates/logic-template.html    |   132 +
 .../templates/standalone-template.html             |    28 +
 .../support_files/templates/style-template.html    |    15 +
 emperor/support_files/vendor/css/chosen-sprite.png |   Bin 0 -> 538 bytes
 .../support_files/vendor/css/chosen-sprite at 2x.png  |   Bin 0 -> 738 bytes
 emperor/support_files/vendor/css/chosen.min.css    |     3 +
 .../vendor/css/font/context-menu-icons.eot         |   Bin 0 -> 4420 bytes
 .../vendor/css/font/context-menu-icons.ttf         |   Bin 0 -> 4212 bytes
 .../vendor/css/font/context-menu-icons.woff        |   Bin 0 -> 2732 bytes
 .../vendor/css/font/context-menu-icons.woff2       |   Bin 0 -> 2196 bytes
 .../css/images/ui-bg_glass_55_fbf9ee_1x400.png     |   Bin 0 -> 335 bytes
 .../css/images/ui-bg_glass_65_ffffff_1x400.png     |   Bin 0 -> 207 bytes
 .../css/images/ui-bg_glass_75_dadada_1x400.png     |   Bin 0 -> 262 bytes
 .../css/images/ui-bg_glass_75_e6e6e6_1x400.png     |   Bin 0 -> 262 bytes
 .../css/images/ui-bg_glass_95_fef1ec_1x400.png     |   Bin 0 -> 332 bytes
 .../ui-bg_highlight-soft_75_cccccc_1x100.png       |   Bin 0 -> 280 bytes
 .../ui-bg_highlight-soft_75_ffe45c_1x100.png       |   Bin 0 -> 328 bytes
 .../vendor/css/images/ui-icons_222222_256x240.png  |   Bin 0 -> 6922 bytes
 .../vendor/css/images/ui-icons_2e83ff_256x240.png  |   Bin 0 -> 4549 bytes
 .../vendor/css/images/ui-icons_454545_256x240.png  |   Bin 0 -> 6992 bytes
 .../vendor/css/images/ui-icons_888888_256x240.png  |   Bin 0 -> 6999 bytes
 .../vendor/css/images/ui-icons_cd0a0a_256x240.png  |   Bin 0 -> 4549 bytes
 emperor/support_files/vendor/css/jquery-ui.min.css |     7 +
 .../vendor/css/jquery.contextMenu.min.css          |    15 +
 .../support_files/vendor/css/slick.grid.min.css    |     1 +
 emperor/support_files/vendor/css/spectrum.min.css  |     1 +
 emperor/support_files/vendor/js/Blob.js            |    16 +
 emperor/support_files/vendor/js/FileSaver.min.js   |     2 +
 .../support_files/vendor/js/chosen.jquery.min.js   |     2 +
 emperor/support_files/vendor/js/chroma.min.js      |    33 +
 emperor/support_files/vendor/js/d3.min.js          |     5 +
 .../support_files/vendor/js/jquery-2.1.4.min.js    |     4 +
 emperor/support_files/vendor/js/jquery-ui.min.js   |    13 +
 .../vendor/js/jquery.contextMenu.min.js            |    18 +
 .../vendor/js/jquery.event.drag-2.2.min.js         |     6 +
 .../vendor/js/jquery.ui.position.min.js            |     4 +
 .../support_files/vendor/js/require-2.1.22.min.js  |    37 +
 emperor/support_files/vendor/js/slick.core.min.js  |     1 +
 .../support_files/vendor/js/slick.editors.min.js   |     1 +
 .../vendor/js/slick.formatters.min.js              |     1 +
 emperor/support_files/vendor/js/slick.grid.min.js  |     2 +
 emperor/support_files/vendor/js/spectrum.min.js    |     1 +
 .../vendor/js/three.js-plugins/ColorConverter.js   |    64 +
 .../vendor/js/three.js-plugins/Detector.js         |    78 +
 .../vendor/js/three.js-plugins/OrbitControls.js    |  1115 +
 .../vendor/js/three.js-plugins/Projector.js        |   921 +
 .../vendor/js/three.js-plugins/SVGRenderer.js      |   519 +
 emperor/support_files/vendor/js/three.min.js       |   870 +
 emperor/support_files/vendor/js/underscore-min.js  |     6 +
 examples/build.py                                  |    57 +
 examples/costello/mapping-file.txt                 |   603 +
 examples/costello/unweighted_unifrac_pc.txt        |   426 +
 examples/evident.ipynb                             |   417 +
 examples/images/costello-all.png                   |   Bin 0 -> 246498 bytes
 examples/images/costello-colored.png               |   Bin 0 -> 219922 bytes
 examples/images/costello.png                       |   Bin 0 -> 162347 bytes
 examples/images/distance-matrix.png                |   Bin 0 -> 127113 bytes
 examples/images/glitch.gif                         |   Bin 0 -> 619226 bytes
 examples/images/js-doc.png                         |   Bin 0 -> 608082 bytes
 examples/images/knight-logo.png                    |   Bin 0 -> 352700 bytes
 examples/images/main-doc.png                       |   Bin 0 -> 643803 bytes
 examples/images/microbes-metric.png                |   Bin 0 -> 1891951 bytes
 examples/images/microbes.png                       |   Bin 0 -> 1925687 bytes
 examples/images/python-doc-2.png                   |   Bin 0 -> 524954 bytes
 examples/images/python-doc.png                     |   Bin 0 -> 658546 bytes
 examples/images/qiime_logo_large.png               |   Bin 0 -> 10901 bytes
 examples/images/table-2.png                        |   Bin 0 -> 62541 bytes
 examples/images/table.png                          |   Bin 0 -> 65581 bytes
 examples/images/vroom.png                          |   Bin 0 -> 7106344 bytes
 examples/keyboard.ipynb                            |   295 +
 examples/keyboard/mapping-file.txt                 |   116 +
 examples/keyboard/otu-table.biom                   |   Bin 0 -> 926963 bytes
 examples/keyboard/unweighted-unifrac.even1000.txt  |    90 +
 examples/scipy-2016.ipynb                          |  4304 +++
 examples/tips.csv                                  |   245 +
 licenses/nb-slideshow-template.txt                 |    30 +
 licenses/numpydoc.txt                              |     1 +
 licenses/scikit-learn.txt                          |    35 +
 licenses/scipy.txt                                 |    31 +
 .../sphinx-bootstrap-theme.txt                     |     2 +-
 licenses/ssw.txt                                   |    46 +
 tests/__init__.py                                  |     7 +
 tests/_test_core_strings.py                        |   544 +
 tests/javascript_tests/index.html                  |   210 +
 tests/javascript_tests/qunit/qunit-min.css         |    11 +
 tests/javascript_tests/qunit/qunit-min.js          |    11 +
 tests/javascript_tests/runner.js                   |   165 +
 tests/javascript_tests/test_animate.js             |   328 +
 tests/javascript_tests/test_axes_controller.js     |   146 +
 .../javascript_tests/test_color_view_controller.js |   544 +
 tests/javascript_tests/test_decomposition_model.js |   633 +
 tests/javascript_tests/test_decomposition_view.js  |   218 +
 tests/javascript_tests/test_draw.js                |   164 +
 tests/javascript_tests/test_plottable.js           |   106 +
 .../javascript_tests/test_scale_view_controller.js |   213 +
 tests/javascript_tests/test_sceneplotview3d.js     |   529 +
 tests/javascript_tests/test_shape_controller.js    |   189 +
 tests/javascript_tests/test_trajectory.js          |   528 +
 tests/javascript_tests/test_util.js                |   161 +
 tests/javascript_tests/test_view_controller.js     |   444 +
 .../javascript_tests/test_visibility_controller.js |   145 +
 .../make_emperor/euclidian_pc.txt                  |    22 +
 tests/test_core.py                                 |   152 +
 tests/test_data/.some-hidden-file                  |     0
 tests/test_data/dir-with-only-hidden-files/.1.txt  |     0
 tests/test_data/dir-with-only-hidden-files/.2.txt  |     0
 tests/test_data/dir-with-only-hidden-files/.3.txt  |     0
 tests/test_data/dir-with-only-hidden-files/.4.txt  |     0
 tests/test_data/procrustes_results.txt             |     0
 ...unweighted_unifrac_pc_transformed_reference.txt |     0
 .../weighted_unifrac_pc_transformed_q1.txt         |     0
 tests/test_pandas.py                               |   105 +
 tests/test_parse.py                                |   106 +
 tests/test_pycogent_backports/test_procrustes.py   |   139 -
 255 files changed, 27541 insertions(+), 53166 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..2b656d1
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,127 @@
+Contributing to Emperor
+=======================
+
+[Emperor](http://biocore.github.io/emperor/) is an open source software package, and we welcome community contributions. You can find the source code and test code for Emperor under public revision control in the Emperor git repository on [GitHub](https://github.com/biocore/emperor). We very much welcome contributions.
+
+This document covers what you should do to get started with contributing to Emperor. You should read this whole document before considering submitting code to Emperor. This will save time for both you and the Emperor developers.
+
+Type of Submissions
+-------------------
+
+Some of the types of contributions we're interested in are new features (big or small, but for big ones it's generally a good idea to ask us if we're interested in including it before starting development), bug fixes, and documentation updates, additions, and fixes.  When considering submitting a new feature to Emperor, you should begin by posting an issue to the [Emperor issue tracker](https://github.com/biocore/emperor/issues). The information that you include in that post will differ  [...]
+
+* For new features, you'll want to describe why the functionality that you are proposing to add is relevant. For it to be relevant, it should be demonstrably useful to Emperor users. This typically means that a new analytic method is implemented (you should describe why it's useful, ideally including a link to a paper that uses this method), or an existing method is enhanced (your implementation matches the performance of the pre-existing method while reducing runtime, memory consumption [...]
+
+* For bug fixes, you should provide a detailed description of the bug so other developers can reproduce it. We take bugs in Emperor very seriously. Bugs can be related to errors in code, documentation, or tests. Errors in documentation or tests are usually updated in the next major release of Emperor. Errors in code that could result in incorrect results or inability to access certain functionality may result in a new minor release of Emperor.
+
+ You should include the following information in your bug report:
+
+ 1. The exact command or function call that you issue to create the bug.
+ 2. A link to all necessary input files for reproducing the bug. These files should only be as large as necessary to create the bug. This is *extremely* useful to other developer, and it is likely that if you don't provide this information you'll get a response asking for it. Often this process helps you to better understand the bug as well.
+ 3. The platform you are using (browser version and operating system).
+
+For documentation additions, you should first post an issue describing what you propose to add, where you'd like to add it in the documentation, and a description of why you think it's an important addition. For documentation improvements and fixes, you should post an issue describing what is currently wrong or missing, and how you propose to address it. For more information about building and contributing to Emperor's documentation, see [this guide](doc/README.md).
+
+When you post your issue, the Emperor developers will respond to let you know if we agree with the addition or change. It's very important that you go through this step to avoid wasting time working on a feature that we are not interested in including in Emperor.
+
+
+Getting started: "quick fixes"
+------------------------------
+
+Some of our issues are labeled as ``quick fix``. Working on [these issues](https://github.com/biocore/Emperor/issues?direction=desc&labels=quick+fix&milestone=&page=1&sort=updated&state=open) is a good way to get started with contributing to Emperor. These are usually small bugs or documentation errors that will only require one or a few lines of code to fix. Getting started by working on one of these issues will allow you to familiarize yourself with our development process before commi [...]
+
+
+Code Review
+-----------
+
+When you submit code to Emperor, it will be reviewed by one or more Emperor developers. These reviews are intended to confirm a few points:
+
+* Your code is sufficiently well-tested (see Testing Guidelines below).
+* Your code adheres to our Coding Guidelines (see Coding Guidelines below).
+* Your code is sufficiently well-documented (see Coding Guidelines below).
+* Your code provides relevant changes or additions to Emperor (Type of Submissions above).
+
+This process is designed to ensure the quality of Emperor, and can be a very useful experience for new developers.
+
+Particularly for big changes, if you'd like feedback on your code in the form of a code review as you work, you should request help in the issue that you created and one of the Emperor developers will work with you to perform regular code reviews. This can greatly reduce development time (and frustration) so we highly recommend that new developers take advantage of this rather than submitting a pull request with a massive amount of code in one chunk. That can lead to frustration when the [...]
+
+
+Submitting code to Emperor
+-----------------------------
+
+Emperor is hosted on [GitHub](http://www.github.com), and we use GitHub's [Pull Request](https://help.github.com/articles/using-pull-requests) mechanism for accepting submissions. You should go through the following steps to submit code to Emperor.
+
+1. Begin by [creating an issue](https://github.com/biocore/Emperor/issues) describing your proposed change. This should include a description of your proposed change (is it a new feature, a bug fix, etc.), and note in the issue description that you want to work on it. Once you hear back from a maintainer that it is OK to make changes (i.e., they dont't have local edits, they agree with the change you'd like to make, and they're comfortable with you editing their code), we will assign the [...]
+
+2. [Fork](https://help.github.com/articles/fork-a-repo) the Emperor repository on the GitHub website to your GitHub account.
+
+3. Clone your forked repository to the system where you'll be developing with ``git clone``.
+
+4. Ensure that you have the latest version of all files (especially important if you cloned a long time ago, but you'll need to do this before submitting changes regardless). You should do this by adding Emperor as a remote repository and then pulling from that repository. You'll only need to run the ``git remote`` step one time:
+```
+git checkout master
+git remote add upstream https://github.com/biocore/emperor.git
+git pull upstream master
+```
+
+5. Create a new topic branch that you will make your changes in with ``git checkout -b``:
+```
+git checkout -b my-topic-branch
+```
+
+6. Run ``python tests/all_tests.py --emperor_scripts_dir scripts`` to confirm that the tests pass before you make any changes.
+
+7. Make your changes, add them (with ``git add``), and commit them (with ``git commit``). Don't forget to update associated scripts and tests as necessary. You should make incremental commits, rather than one massive commit at the end. Write descriptive commit messages to accompany each commit.
+
+8. When you think you're ready to submit your code, again ensure that you have the latest version of all files in case some changed while you were working on your edits. You can do this by merging master into your topic branch:
+```
+git checkout my-topic-branch
+git pull upstream master
+```
+
+9. Run ``python tests/all_tests.py --emperor_scripts_dir scripts`` to ensure that your changes did not cause anything expected to break.
+
+10. Once the tests pass, you should push your changes to your forked repository on GitHub using:
+```
+git push origin my-topic-branch
+```
+
+11. Issue a [pull request](https://help.github.com/articles/using-pull-requests) on the GitHub website to request that we merge your branch's changes into Emperor's master branch. One of the Emperor developers will review your code at this stage. If we request changes (which is very common), *don't issue a new pull request*. You should make changes on your topic branch, and commit and push them to GitHub. Your pull request will update automatically.
+
+12. Once your pull request is submitted and if there are no merge conflicts, you should see an automatic message posted by [@emperor-helper](https://github.com/emperor-helper). The message will include a link to the built script usage examples (the use-cases that are described at the top of `make_emperor.py --help`). The goal is to provide an easy way for reviewers and developers to verify that the GUI is functional and works as expected **with your new changes**. For more information ab [...]
+
+
+Coding Guidelines
+-----------------
+
+For **Python** code, we adhere to the [PEP 8](http://www.python.org/dev/peps/pep-0008/) python coding guidelines for code and documentation standards. For **JavaScript** code, we adhere to the [Google closure](https://google.github.io/styleguide/javascriptguide.xml) javascript coding standards, and use [JSDoc](http://usejsdoc.org/) to compile all javascript documentation. When using the closure linter, we allow the `module`, `function`, `constructs`, `alias`, and `default` custom JSDoc t [...]
+
+Before submitting any code to Emperor, you should read these carefully and apply the guidelines in your code. As part of our automated testing, we make sure that all code passes linter standards and documentation compiles. We use the [gjslint](https://developers.google.com/closure/utilities/) linter to test javascript code with the `--custom_jsdoc_tags module,function,constructs,alias,default` modifier, and the [flake8](https://pypi.python.org/pypi/flake8) linter to test python code.
+
+Testing Guidelines
+------------------
+
+All code that is added to Emperor must be unit tested, and the unit test code must be submitted in the same pull request as the library code that you are submitting. We will only merge code that is unit tested and that passes the [continuous integration build](https://github.com/biocore/emperor/blob/master/.travis.yml), this build verifies that the:
+
+- Full test suite executes without errors (including JavaScript and script usage tests).
+- All python code in Emperor is PEP8-compliant.
+- All javascript code in Emperor is google closure compliant.
+- All code is valid in Python 2.7.x.
+- The documentation can be built correctly.
+
+Emperor adheres to scikit-bio's coding guidelines see our [expectations for unit tests](http://scikit-bio.org/development/coding_guidelines.html). You should review the unit test section before working on your test code.
+
+If you are adding a new parameter to a command line utility, make sure you add a new usage example to the script and that you add the relevant files to `tests/script_test_data/`.
+
+Tests can be executed using the `all_tests.py` script located inside the tests directory. This script will execute:
+
+- Python unit tests.
+- Script usage unit tests.
+- JavaScript unit tests (these depend on the [phantom.js](http://phantomjs.org) being installed on your system), but you can also execute them opening `tests/javascript_tests/index.html` in your browser (we recommend Google Chrome).
+
+After this script is executed a summary of the tests that failed will be printed to the screen.
+
+Getting help with git
+=====================
+
+If you're new to ``git``, you'll probably find [gitref.org](http://gitref.org/) helpful.
diff --git a/debian/changelog b/debian/changelog
index 9515e5d..67d915b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,6 @@
-emperor (1.0.0beta5-1) UNRELEASED; urgency=medium
+emperor (1.0.0-beta.5-1) UNRELEASED; urgency=medium
 
-  * Team upload.
-  * Packaged software
-  * Setup.py fixed
+  * packaging errors fixed
 
- -- Kerim ÖLÇER <lcr at debian>  Wed, 19 Oct 2016 22:19:34 +0300
+ -- Kerim Ölçer <kerimlcr at gmail.com>  Wed, 19 Oct 2016 22:19:34 +0300
 
diff --git a/debian/control b/debian/control
index 9dbc2df..f439dce 100644
--- a/debian/control
+++ b/debian/control
@@ -2,19 +2,54 @@ Source: emperor
 Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
 Uploaders: Kerim Ölçer <kerimlcr at gmail.com>,
            Afif Elghraoui <afif at debian.org>
-Section: science
+Section: sience
 Priority: optional
-Build-Depends: python-all,
-               debhelper (>= 10)
+Build-Depends: debhelper (>= 10), dh-python, python-all, python-setuptools, python3-all, python3-setuptools
 Standards-Version: 3.9.8
+Homepage: https://biocore.github.io/emperor/
+X-Python-Version: >= 2.7
+X-Python3-Version: >= 3.4
 Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/emperor.git
 Vcs-Git: https://anonscm.debian.org/git/debian-med/emperor.git
-Homepage: https://biocore.github.io/emperor/
 
-Package: emperor
+Package: python-emperor
+Architecture: all
+Depends: ${python:Depends}, ${misc:Depends}, python-numpy, python-scipy, python-click, python-pandas, python-jinja2, python-future
+Suggests: python-emperor-doc
+Description: visualizing high-throughput microbial community data
+ Emperor is an interactive next generation tool for the analysis,
+ visualization and understanding of high throughput microbial
+ ecology datasets.
+ .
+ Due to its tailor-made graphical user interface, delving into a new
+ dataset to elucidate the patterns hidden in the data, has never been
+ easier. Emperor brings a rich set of customizations and modifications
+ that can be integrated into any QIIME or scikit-bio compliant dataset;
+ with lightweight data files and hardware accelerated graphics,
+ constitutes itself as the state of the art for analyzing N-dimensional
+ data using principal coordinates analysis.
+
+Package: python3-emperor
+Architecture: all
+Depends: ${python3:Depends}, ${misc:Depends}, python3-numpy, python3-scipy, python3-click, python3-pandas, python3-jinja2, python3-future
+Suggests: python-emperor-doc
+Description: visualizing high-throughput microbial community data
+ Emperor is an interactive next generation tool for the analysis,
+ visualization and understanding of high throughput microbial
+ ecology datasets.
+ .
+ Due to its tailor-made graphical user interface, delving into a new
+ dataset to elucidate the patterns hidden in the data, has never been
+ easier. Emperor brings a rich set of customizations and modifications
+ that can be integrated into any QIIME or scikit-bio compliant dataset;
+ with lightweight data files and hardware accelerated graphics,
+ constitutes itself as the state of the art for analyzing N-dimensional
+ data using principal coordinates analysis.
+
+Package: python-emperor-doc
 Architecture: all
-Depends: ${misc:Depends},
-         ${python:Depends}
+Section: doc
+Depends: ${sphinxdoc:Depends}, ${misc:Depends}
 Description: visualizing high-throughput microbial community data
  Emperor is an interactive next generation tool for the analysis,
  visualization and understanding of high throughput microbial
diff --git a/debian/copyright b/debian/copyright
index 6fd2961..01e450c 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -51,52 +51,24 @@ Copyright: (c) 2011 [Eli Grey](http://eligrey.com).
 License: MIT
 
 Files: debian/*
-Copyright: © 2014 Tim Booth <tbooth at ceh.ac.uk>
-             2014 Andreas Tille <tille at debian.org>
+Copyright: 2017 Kerim Ölçer <kerimlcr at gmail.com>
 License: MIT
 
-License: BSDlike
- All rights reserved.
- .
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- .
- * Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
- .
- * Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
- .
- * The name Kai Chang may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
- .
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE,
- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 License: MIT
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- . 
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
  .
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/doc-base b/debian/doc-base
deleted file mode 100644
index d98d819..0000000
--- a/debian/doc-base
+++ /dev/null
@@ -1,8 +0,0 @@
-Document: python-emperor
-Title: A tool for visualizing high-throughput microbial community data
-Author: The EMPeror Project
-Section: Science/Biology
-
-Format: html
-Files: /usr/share/doc/emperor/html/*
-Index: /usr/share/doc/emperor/html/index.html
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 05ceb5f..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,2 +0,0 @@
-README.md
-html
diff --git a/debian/files b/debian/files
new file mode 100644
index 0000000..1135abb
--- /dev/null
+++ b/debian/files
@@ -0,0 +1,4 @@
+emperor_1.0.0-beta.5-1_amd64.buildinfo sience optional
+python-emperor-doc_1.0.0-beta.5-1_all.deb doc optional
+python-emperor_1.0.0-beta.5-1_all.deb sience optional
+python3-emperor_1.0.0-beta.5-1_all.deb sience optional
diff --git a/debian/make_emperor.1 b/debian/make_emperor.1
deleted file mode 100644
index d16a70e..0000000
--- a/debian/make_emperor.1
+++ /dev/null
@@ -1,218 +0,0 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.40.4.
-.TH EMPEROR: "1" "February 2014" "Version: make_emperor 0.9.3" "User Commands"
-.SH NAME
-make_emperor \- Create PCoA plots to be visualised with Emperor.
-.SH SYNOPSIS
-.B make_emperor
-[\fIoptions\fR] \fI{-i/--input_coords INPUT_COORDS -m/--map_fp MAP_FP}\fR
-.SH DESCRIPTION
-[] indicates optional input (order unimportant)
-.PP
-{} indicates required input (order unimportant)
-.PP
-This script automates the creation  of three\-dimensional PCoA plots to be visualized with Emperor using Google Chrome or another comaptible browser.  Note the script has been renamed from make_emperor.py to make_emperor to comply with Debian guidelines.
-.PP
-Example usage:
-Print help message and exit
-.IP
-make_emperor \fB\-h\fR
-.PP
-Plot PCoA data: Visualize the a PCoA file colored using a corresponding mapping file:
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-o\fR emperor_output
-.PP
-Coloring by metadata mapping file: 
-Additionally, using the supplied mapping file and a specific category or any combination of the available categories. When using the -b option, the user can specify the coloring for multiple header names, where each header is separated by a comma. The user can also combine mapping headers and color by the combined headers that are created by inserting an '&&' between the input header names. Color by 'Treatment' and by the result of concatenating the 'DOB' category and the 'Treatment' category:
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-b\fR 'Treatment&&DOB,Treatment' \fB\-o\fR emperor_colored_by
-.PP
-PCoA plot with an explicit axis: Create a PCoA plot with an axis of the plot representing the 'DOB' of the samples. This option is useful when presenting a gradient from your metadata e. g. 'Time' or 'pH':
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-a\fR DOB \fB\-o\fR pcoa_dob
-.PP
-PCoA plot with an explicit axis and using --missing_custom_axes_values: Create a PCoA plot with an axis of the plot representing the 'DOB' of the samples and define the position over the gradient of those samples missing a numeric value; in this case we are going to plot the samples in the value 20060000. You can select for each explicit axis which value you want to use for the missing values:
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map_modified.txt \fB\-a\fR DOB \fB\-o\fR pcoa_dob_with_missing_custom_axes_values \fB\-x\fR 'DOB:20060000'
-.PP
-PCoA plot with an explicit axis and using \fB\-\-missing_custom_axes_values\fR but setting different values based on another column: Create a PCoA plot with an axis of the plot representing the 'DOB' of the samples and defining the position over the gradient of those samples missing a numeric value but using as reference another column of the mapping file. In this case we are going to plot the samples that are Control on the Treatment column on 20080220 and on 20080240 those that are Fast
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map_modified.txt \fB\-a\fR DOB \fB\-o\fR pcoa_dob_with_missing_custom_axes_with_multiple_values \fB\-x\fR 'DOB:Treatment==Control=20080220' \fB\-x\fR 'DOB:Treatment==Fast=20080240'
-.PP 
-Jackknifed principal coordinates analysis plot: Create a jackknifed PCoA plot (with confidence intervals for each sample) passing as the input a directory of coordinates files (where each file corresponds to a different OTU table) and use the standard deviation method to compute the dimensions of the ellipsoids surrounding each sample:
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc \fB\-m\fR Fasting_Map.txt \fB\-o\fR jackknifed_pcoa \fB\-e\fR sdev
-.PP
-Jackknifed PCoA plot with a master coordinates file: Passing a master coordinates file (--master_pcoa) will display the ellipsoids centered by the samples in this file:
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc \fB\-s\fR unweighted_unifrac_pc/pcoa_unweighted_unifrac_rarefaction_110_5.txt \fB\-m\fR Fasting_Map.txt \fB\-o\fR jackknifed_with_master
-.PP
-BiPlots: To see which taxa are the ten more prevalent in the different areas of the PCoA plot, you need to pass a summarized taxa file i. e. the output of summarize_taxa.py. Note that if the the '\-\-taxa_fp' has fewer than 10 taxa, the script will default to use all.
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-t\fR otu_table_L3.txt \fB\-o\fR biplot
-.PP
-BiPlots with extra options: To see which are the three most prevalent taxa and save the coordinates where these taxa are centered, you can use the \fB\-n\fR (number of taxa to keep) and the \fB\-\-biplot_fp\fR (output biplot file path) options.
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-t\fR otu_table_L3.txt \fB\-o\fR biplot_options \fB\-n\fR 3 \fB\-\-biplot_fp\fR biplot.txt
-.PP
-Drawing connecting lines between samples: To draw lines betwen samples within a category use the '\-\-add_vectors' option. For example to connect the lines by the 'Treatment' category.
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-o\fR vectors \fB\-\-add_vectors\fR Treatment
-.PP
-Drawing connecting lines between samples with an explicit axis: To draw lines between samples within a category of the mapping file and have them sorted by a category that's explicitly represented in the 3D plot use the '\-\-add_vectors' and the '\-a' option.
-.IP
-make_emperor \fB\-i\fR unweighted_unifrac_pc.txt \fB\-m\fR Fasting_Map.txt \fB\-\-add_vectors\fR Treatment,DOB \fB\-a\fR DOB \fB\-o\fR sorted_by_DOB
-.PP
-Compare two coordinate files: To draw replicates of the same samples like for a procustes plot.
-.IP
-make_emperor \fB\-i\fR compare \fB\-m\fR Fasting_Map.txt \fB\-\-compare_plots\fR \fB\-o\fR comparison
-.SH OPTIONS
-.TP
-\fB\-\-version\fR
-show program's version number and exit
-.TP
-\fB\-h\fR, \fB\-\-help\fR
-show this help message and exit
-.TP
-\fB\-v\fR, \fB\-\-verbose\fR
-Print information during execution \fB\-\-\fR useful for
-debugging [default: False]
-.TP
-\fB\-\-number_of_axes\fR=\fINUMBER_OF_AXES\fR
-Number of axes to be incorporated in the plot. Only 3
-will be displayed at any given time but this option
-modifies how many axes you can use for your
-visualization. Note that Emperor will only use the
-axes that explain more than 0.5% (this will be shown
-as 1% in the GUI)of the variability [default: 10]
-.TP
-\fB\-a\fR CUSTOM_AXES, \fB\-\-custom_axes\fR=\fICUSTOM_AXES\fR
-Comma\-separated list of metadata categories to use as
-custom axes in the plot. For instance, if there is a
-time category and you would like to see the samples
-plotted on that axis instead of PC1, PC2, etc., you
-would pass time as the value of this option.  Note: if
-there is any non\-numeric data in the metadata column,
-an error will be presented [default: none]
-.TP
-\fB\-\-add_unique_columns\fR
-Add to the output categories of the mapping file the
-columns where all values are different. Note: if the
-result of one of the concatenated fields in \fB\-\-color_by\fR
-is a column where all values are unique, the resulting
-column will get removed as well [default: False]
-.TP
-\fB\-\-add_vectors\fR=\fIADD_VECTORS\fR
-Comma\-sparated category(ies) used to add connecting
-lines (vectors) between samples. The first category
-specifies the samples that will be connected by the
-vectors, whilst the second category (optionally)
-determines the order in which the samples will be
-connected. [default: [None, None]]
-.TP
-\fB\-b\fR COLOR_BY, \fB\-\-color_by\fR=\fICOLOR_BY\fR
-Comma\-separated list of metadata categories (column
-headers) to color by in the plots. The categories must
-match the name of a column header in the mapping file
-exactly. Multiple categories can be listed by comma
-separating them without spaces. The user can also
-combine columns in the mapping file by separating the
-categories by "&&" without spaces. [default=color by
-all categories except ones where all values are
-different]
-.TP
-\fB\-\-biplot_fp\fR=\fIBIPLOT_FP\fR
-Output filepath that will contain the coordinates
-where each taxonomic sphere is centered. [default:
-none]
-.TP
-\fB\-c\fR, \fB\-\-compare_plots\fR
-Passing a directory with the \fB\-i\fR (\fB\-\-input_coords\fR)
-option in combination with this flag results in a set
-of bars connecting the replicated samples across all
-the input files. [default=False]
-.TP
-\fB\-e\fR ELLIPSOID_METHOD, \fB\-\-ellipsoid_method\fR=\fIELLIPSOID_METHOD\fR
-Used only when plotting ellipsoids for jackknifed beta
-diversity (i.e. using a directory of coord files
-instead of a single coord file). Valid values are
-"IQR" (for inter\-quartile ranges) and "sdev" (for
-standard deviation). [default=IQR]
-.TP
-\fB\-\-ignore_missing_samples\fR
-This will overpass the error raised when the
-coordinates file contains samples that are not present
-in the mapping file. Be aware that this is very
-misleading as the PCoA is accounting for all the
-samples and removing some samples could lead to
-erroneous/skewed interpretations.
-.TP
-\fB\-n\fR N_TAXA_TO_KEEP, \fB\-\-n_taxa_to_keep\fR=\fIN_TAXA_TO_KEEP\fR
-Number of taxonomic groups from the "\-\-taxa_fp" file
-to display. Passing "\-1" will cause to display all the
-taxonomic groups, this option is only used when
-creating BiPlots. [default=10]
-.TP
-\fB\-s\fR MASTER_PCOA, \fB\-\-master_pcoa\fR=\fIMASTER_PCOA\fR
-Used only when the input is a directory of coordinate
-files i. e. for jackknifed beta diversity plot or for
-a coordinate comparison plot (procrustes analysis).
-The coordinates in this file will be the center of
-each ellipsoid in the case of a jackknifed PCoA plot
-or the center where the connecting arrows originate
-from for a comparison plot. [default: arbitrarily
-selected file from the input directory for a
-jackknifed plot or None for a comparison plot in this
-case one file will be connected to the next one and so
-on]
-.TP
-\fB\-t\fR TAXA_FP, \fB\-\-taxa_fp\fR=\fITAXA_FP\fR
-Path to a summarized taxa file (i. e. the output of
-summarize_taxa.py). This option is only used when
-creating BiPlots. [default=none]
-.TP
-\fB\-x\fR MISSING_CUSTOM_AXES_VALUES, \fB\-\-missing_custom_axes_values\fR=\fIMISSING_CUSTOM_AXES_VALUES\fR
-Option to override the error shown when the catergory
-used in '\-\-custom_axes' has non\-numeric values in the
-mapping file. The basic format is
-custom_axis:new_value. For example, if you want to
-plot in time 0 all the samples that do not have a
-numeric value in the column Time. you would pass \fB\-x\fR
-"Time:0". Additionally, you can pass this format custo
-m_axis:other_column==value_in_other_column=new_value,
-with this format you can specify different values
-(new_value) to use in the substitution based on other
-column (other_column) value (value_in_other_column);
-see example above. This option could be used in all
-explicit axes.
-.TP
-\fB\-o\fR OUTPUT_DIR, \fB\-\-output_dir\fR=\fIOUTPUT_DIR\fR
-path to the output directory that will contain the
-PCoA plot. [default: emperor]
-.TP
-\fB\-\-number_of_segments\fR=\fINUMBER_OF_SEGMENTS\fR
-the number of segments to generate any spheres, this
-includes the samples, the taxa (biplots), and the
-confidence intervals (jackknifing). Higher values will
-result in better quality but can make the plots less
-responsive, also it will make the resulting SVG images
-bigger. The value should be between 4 and 14.
-[default: 8]
-.IP
-REQUIRED options:
-.IP
-The following options must be provided under all circumstances.
-.TP
-\fB\-i\fR INPUT_COORDS, \fB\-\-input_coords\fR=\fIINPUT_COORDS\fR
-Depending on the plot to be generated, can be one of
-the following: (1) Filepath of a coordinates file to
-create a PCoA plot. (2) Directory path to a folder
-containing coordinates files to create a jackknifed
-PCoA plot. (3) Directory path to a folder containing
-coordinates files to compare the coordinates there
-contained when \fB\-\-compare_plots\fR is enabled (useful for
-procustes analysis plots). For directories: hidden
-files, sub\-directories and files suffixed as
-\&'_procrustes_results.txt' [REQUIRED]
-.TP
-\fB\-m\fR MAP_FP, \fB\-\-map_fp\fR=\fIMAP_FP\fR
-path to a metadata mapping file [REQUIRED]
diff --git a/debian/manpages b/debian/manpages
deleted file mode 100644
index d2cbf45..0000000
--- a/debian/manpages
+++ /dev/null
@@ -1 +0,0 @@
-debian/make_emperor.1
diff --git a/debian/patches/fetch_examples_from_web.patch b/debian/patches/fetch_examples_from_web.patch
deleted file mode 100644
index be6dce6..0000000
--- a/debian/patches/fetch_examples_from_web.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Update: Tue, 25 Feb 2014 15:17:10 +0100
-Description: The ZIP archive files/files.zip was removed from
- the source archive since it contained some *.js files without
- source and before we run into licensing trouble it is way more
- simple to let people who want to test the examples from the
- tutorial download this directly from the internet
-
---- a/doc/tutorial_index.html
-+++ b/doc/tutorial_index.html
-@@ -118,7 +118,7 @@
-             <br>
-             The dataset that we will use to exemplify Emperor’s functionality, comes from the <a href="http://www.pnas.org/content/107/14/6477.long">Fierer et. al. 2010</a> article, where three individuals and their keyboards were sampled, Figure 1.
-             <br>
--            To get started, first download and unzip these <a href="files/files.zip">files</a>, here you will find a principal coordinates file, and a mapping file. These input files are in the standard format used in <a href="http://www.qiime.org">QIIME</a>. Before continuing with the tutorial make sure you have the latest version of <a href=" https://www.google.com/intl/en/chrome/browser/">Google Chrome</a> installed in your computer. The sections described in this tutorial are:
-+            To get started, first download and unzip these <a href="http://biocore.github.io/emperor/files/files.zip">files</a>, here you will find a principal coordinates file, and a mapping file. These input files are in the standard format used in <a href="http://www.qiime.org">QIIME</a>. Before continuing with the tutorial make sure you have the latest version of <a href=" https://www.google.com/intl/en/chrome/browser/">Google Chrome</a> installed in your computer. The sections desc [...]
-             <br>
-             <ul >
-             <li><a class="lead" href="#section0">Command Line Interface</a></li>
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 3da8193..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-setup-fix
diff --git a/debian/rules b/debian/rules
index 595f0a0..529aabc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,31 +1,19 @@
 #!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#export DH_VERBOSE = 1
 
-# This file was automatically generated by stdeb 0.8.5 at
-# Wed, 19 Oct 2016 22:16:02 +0300
+export PYBUILD_NAME=emperor
 
 %:
-	dh $@ --with python2 --buildsystem=python_distutils
-
-
-override_dh_auto_clean:
-	python setup.py clean -a
-	find . -name \*.pyc -exec rm {} \;
-
-
-
-override_dh_auto_build:
-	python setup.py build --force
-
-
-
-override_dh_auto_install:
-	python setup.py install --force --root=debian/python-emperor --no-compile -O0 --install-layout=deb  
-
-
-
-override_dh_python2:
-	dh_python2 --no-guessing-versions
-
+	dh $@ --with python2,python3 --buildsystem=pybuild
 
 
+# If you need to rebuild the Sphinx documentation
+# Add spinxdoc to the dh --with line
+#override_dh_auto_build:
+#	dh_auto_build
+#	PYTHONPATH=. http_proxy='127.0.0.1:9' sphinx-build -N -bhtml        docs/ build/html # HTML generator
+#	PYTHONPATH=. http_proxy='127.0.0.1:9' sphinx-build -N -bman        docs/ build/man # Manpage generator
 
+override_dh_auto_test:
diff --git a/debian/source/options b/debian/source/options
new file mode 100644
index 0000000..cb61fa5
--- /dev/null
+++ b/debian/source/options
@@ -0,0 +1 @@
+extend-diff-ignore = "^[^/]*[.]egg-info/"
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
deleted file mode 100644
index e14782d..0000000
--- a/debian/upstream/metadata
+++ /dev/null
@@ -1,12 +0,0 @@
-Reference:
-  Author: Yoshiki Vázquez-Baeza and Meg Pirrung and Antonio Gonzalez and Rob Knight
-  Title: "EMPeror: a tool for visualizing high-throughput microbial community data"
-  Journal: Gigascience
-  Year: 2013
-  Volume: 2
-  Number: 1
-  Pages: 16
-  DOI: 10.1186/2047-217X-2-16
-  PMID: 24280061
-  URL: http://www.gigasciencejournal.com/content/2/1/16
-  eprint: http://www.gigasciencejournal.com/content/pdf/2047-217X-2-16.pdf
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..4140d7a
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,181 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    = -W
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	rm -rf $(BUILDDIR)/*
+	rm -rf source/scripts/*
+	rm -rf source/generated
+	rm -rf doc/build/jsdoc/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	jsdoc ../emperor/support_files/js/ -d $(BUILDDIR)/jsdoc -c jsdoc-config.json
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Emperor.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Emperor.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/Emperor"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Emperor"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..78ed6ae
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,60 @@
+Emperor documentation
+=====================
+
+This guide contains instructions for building the Emperor documentation, as
+well as guidelines for contributing to the documentation.
+
+**Note:** If you're only interested in viewing the Emperor documentation,
+visit [http://biocore.github.io/emperor/](http://biocore.github.io/emperor/).
+
+Building the documentation
+--------------------------
+
+To build the documentation, you'll need the following Python packages
+installed:
+
+- [Sphinx](http://sphinx-doc.org/) >= 1.2.2
+- [sphinx-bootstrap-theme](https://pypi.python.org/pypi/sphinx-bootstrap-theme/)
+
+An easy way to install the dependencies is via pip:
+
+    pip install Sphinx sphinx-bootstrap-theme
+
+Finally, you will need to install Emperor.
+
+**Important:** The documentation will be built for whatever version of
+Emperor is *currently installed* on your system (i.e., the version imported
+by ```import emperor```). This may not match the code located in this repository.
+You will need to either install this version of Emperor somewhere (e.g., in
+a virtualenv) or point your ```PYTHONPATH``` environment variable to this code,
+*before* building the documentation.
+
+To build the documentation, assuming you are at the top-level Emperor
+directory:
+
+    cd doc
+    make html
+
+The built HTML documentation will be at ```build/html/index.html```.
+
+Contributing to the documentation
+---------------------------------
+
+If you would like to contribute to the documentation, whether by adding
+something entirely new or by modifying existing documentation, please first
+review our [Emperor contribution guide](../CONTRIBUTING.md).
+
+Before submitting your changes, ensure that the documentation builds without
+any errors or warnings, and that there are no broken links:
+
+    make clean
+    make html
+    make linkcheck
+
+### Troubleshooting
+
+If things aren't working correctly, try running ```make clean``` and then
+rebuild the docs. If things still aren't working, try building the docs
+*without* your changes, and see if there are any Sphinx errors or warnings.
+Make note of these, and then see what new errors or warnings are generated when
+you add your changes again.
diff --git a/doc/bootstrap/css/bootstrap-theme.min.css b/doc/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 0000000..dc95d8e
--- /dev/null
+++ b/doc/bootstrap/css/bootstrap-theme.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warnin [...]
+/*# sourceMappingURL=bootstrap-theme.min.css.map */
\ No newline at end of file
diff --git a/doc/bootstrap/css/bootstrap.min.css b/doc/bootstrap/css/bootstrap.min.css
new file mode 100644
index 0000000..4cf729e
--- /dev/null
+++ b/doc/bootstrap/css/bootstrap.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr [...]
+/*# sourceMappingURL=bootstrap.min.css.map */
\ No newline at end of file
diff --git a/doc/bootstrap/fonts/glyphicons-halflings-regular.eot b/doc/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..b93a495
Binary files /dev/null and b/doc/bootstrap/fonts/glyphicons-halflings-regular.eot differ
diff --git a/doc/bootstrap/fonts/glyphicons-halflings-regular.svg b/doc/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..94fb549
--- /dev/null
+++ b/doc/bootstrap/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 15 [...]
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 1 [...]
+<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 1 [...]
+<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-2 [...]
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t- [...]
+<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21  [...]
+<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 [...]
+<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21  [...]
+<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5  [...]
+<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17. [...]
+<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h [...]
+<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 9 [...]
+<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5  [...]
+<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 [...]
+<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -2 [...]
+<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 21 [...]
+<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-4 [...]
+<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q [...]
+<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16 [...]
+<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0 [...]
+<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5 [...]
+<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 [...]
+<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21  [...]
+<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -2 [...]
+<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 [...]
+<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0  [...]
+<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21  [...]
+<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5  [...]
+<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0  [...]
+<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 [...]
+<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 - [...]
+<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5  [...]
+<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141  [...]
+<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t [...]
+<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 [...]
+<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 [...]
+<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q [...]
+<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 - [...]
+<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 [...]
+<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 - [...]
+<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80  [...]
+<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -7 [...]
+<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 1 [...]
+<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100 [...]
+<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375 [...]
+<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 - [...]
+<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 [...]
+<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 [...]
+<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-4 [...]
+<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5  [...]
+<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70 [...]
+<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 [...]
+<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 [...]
+<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2  [...]
+<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 - [...]
+<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5 [...]
+<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17. [...]
+<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15 [...]
+<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14 [...]
+<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212 [...]
+<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -2 [...]
+<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250 [...]
+<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t [...]
+<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h [...]
+<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35 [...]
+<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 [...]
+<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h [...]
+<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 3 [...]
+<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -1 [...]
+<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 [...]
+<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 19 [...]
+<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/doc/bootstrap/fonts/glyphicons-halflings-regular.ttf b/doc/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..1413fc6
Binary files /dev/null and b/doc/bootstrap/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/doc/bootstrap/fonts/glyphicons-halflings-regular.woff b/doc/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..9e61285
Binary files /dev/null and b/doc/bootstrap/fonts/glyphicons-halflings-regular.woff differ
diff --git a/doc/bootstrap/fonts/glyphicons-halflings-regular.woff2 b/doc/bootstrap/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000..64539b5
Binary files /dev/null and b/doc/bootstrap/fonts/glyphicons-halflings-regular.woff2 differ
diff --git a/doc/bootstrap/js/bootstrap.min.js b/doc/bootstrap/js/bootstrap.min.js
new file mode 100644
index 0000000..e79c065
--- /dev/null
+++ b/doc/bootstrap/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:" [...]
+d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data()) [...]
\ No newline at end of file
diff --git a/doc/bootstrap/js/jquery-2.2.3.min.js b/doc/bootstrap/js/jquery-2.2.3.min.js
new file mode 100644
index 0000000..b8c4187
--- /dev/null
+++ b/doc/bootstrap/js/jquery-2.2.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.2.3 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r= [...]
+}catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.inde [...]
+e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.s [...]
diff --git a/doc/files/files.zip b/doc/files/files.zip
new file mode 100644
index 0000000..4a6412b
Binary files /dev/null and b/doc/files/files.zip differ
diff --git a/doc/installation_index.html b/doc/installation_index.html
deleted file mode 100644
index bfc931d..0000000
--- a/doc/installation_index.html
+++ /dev/null
@@ -1,202 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>Emperor</title>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <meta name="description" content="">
-    <meta name="author" content="">
-    <link href="bootstrap/css/bootstrap.css" rel="stylesheet">
-    <style type="text/css">
-      body {
-        padding-top: 20px;
-        padding-bottom: 60px;
-      }
-
-      /* Custom container */
-      .container {
-        margin: 0 auto;
-        max-width: 1000px;
-      }
-      .container > hr {
-        margin: 60px 0;
-      }
-
-      /* Main marketing message and sign up button */
-      .jumbotron {
-        margin: 80px 0;
-        text-align: center;
-      }
-      .jumbotron h1 {
-        font-size: 100px;
-        line-height: 1;
-      }
-      .jumbotron .lead {
-        font-size: 24px;
-        line-height: 1.25;
-      }
-      .jumbotron .btn {
-        font-size: 21px;
-        padding: 14px 24px;
-      }
-
-      /* Supporting marketing content */
-      .marketing {
-        margin: 60px 0;
-      }
-      .marketing p + h4 {
-        margin-top: 28px;
-      }
-
-
-      /* Customize the navbar links to be fill the entire space of the .navbar */
-      .navbar .navbar-inner {
-        padding: 0;
-      }
-      .navbar .nav {
-        margin: 0;
-        display: table;
-        width: 100%;
-      }
-      .navbar .nav li {
-        display: table-cell;
-        width: 1%;
-        float: none;
-      }
-      .navbar .nav li a {
-        font-weight: bold;
-        text-align: center;
-        border-left: 1px solid rgba(255,255,255,.75);
-        border-right: 1px solid rgba(0,0,0,.1);
-      }
-      .navbar .nav li:first-child a {
-        border-left: 0;
-        border-radius: 3px 0 0 3px;
-      }
-      .navbar .nav li:last-child a {
-        border-right: 0;
-        border-radius: 0 3px 3px 0;
-      }
-    </style>
-    <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
-
-    <!-- GitHub ribbon -->
-    <a href="https://github.com/qiime/emperor"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png" alt="Fork me on GitHub"></a>
-    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
-    <!--[if lt IE 9]>
-      <script src="bootstrap/js/html5shiv.js"></script>
-    <![endif]-->
-
-    <!-- Fav and touch icons -->
-    <link rel="shortcut icon" href="img/favicon.ico">
-  </head>
-
-  <body>
-
-    <div class="container">
-
-      <div class="masthead">
-        <a href="index.html"><p align="center"><img src="img/emperor_heading.png" alt="Emperor Logo"></p></a>
-        <div class="navbar">
-          <div class="navbar-inner">
-            <div class="container">
-              <ul class="nav">
-                <li><a href="index.html">Home</a></li>
-                <li><a href="description_index.html">Description</a></li>
-                <li><a href="tutorial_index.html">Tutorial</a></li>
-                <li class="active"><a href="installation_index.html">Installation</a></li>
-                <li><a href="https://github.com/qiime/emperor/issues">Support</a></li>
-              </ul>
-            </div>
-          </div>
-        </div><!-- /.navbar -->
-      </div>
-
-      <!-- Jumbotron -->
-      <div class="jumbotron">
-      </div>
-        <h2>Downloading</h2>
-        <p class="lead" align="justify">
-          Emperor is a python package hosted in <a href="https://github.com/qiime/emperor/">GitHub</a> that relies on <a href="http://www.numpy.org/">NumPy</a> and <a href="ftp://thebeast.colorado.edu/pub/qcli-releases/qcli-0.1.0.tar.gz">qcli</a>. These packages must be installed prior running the <code>setup.py</code> script.
-        </p>
-        <p align="center">
-          <a class="btn btn-large btn-primary" href="https://github.com/qiime/emperor/archive/0.9.2.zip">
-            Download Stable Version
-          </a>
-          <a class="btn btn-large btn-warning" href="https://github.com/qiime/emperor/archive/master.zip">
-            Download Development Version
-          </a>
-        </p>
-        <br>
-        <p class="lead" align="justify">
-          To clone the git repository directly into your machine:
-          <br>
-          <pre><code>git clone git://github.com/qiime/emperor.git</code></pre>
-        </p>
-        <hr>
-        <h2>Installing</h2>
-        <p class="lead" align="justify">
-          To perform a global installation of Emperor, execute the following command from a terminal session:
-          <br>
-          <pre><code>python setup.py install</code></pre>
-        </p>
-        <p class="lead" align="justify">
-          <br>
-          If you do not want to do a global installation, you will have to add the Emperor scripts and libraries to the <code>PATH</code> and <code>PYTHONPATH</code> environment variables. To add these variables to your <code>.bash_profile</code> issue the following terminal commands:
-          <br>
-          <pre><code>echo "export PATH=$HOME/emperor_bin/:$PATH" >> ~/.bash_profile<br>echo "export PYTHONPATH=$HOME/emperor_lib/:$PYTHONPATH" >> ~/.bash_profile<br>python setup.py install --install-scripts=~/emperor_bin/ --install-purelib=~/emperor_lib/ --install-lib=~/emperor_lib/</code></pre>
-          <br>
-        </p>
-        <p class="lead" align="justify">
-          Alternatively Emperor can be installed from the Python Package Index (<a href="https://pypi.python.org/pypi">PyPi</a>)
-          <br>
-          <pre><code>pip install emperor</code></pre>
-        </p>
-        <br>
-        <h2>Verifying your installation</h2>
-        <p class="lead" align="justify">
-          To test for a correct installation, open a new terminal window and issue the following command to see the help of <code>make_emperor.py</code>:
-          <pre><code>make_emperor.py -h
-Usage: make_emperor.py [options] {-i/--input_coords INPUT_COORDS -m/--map_fp MAP_FP}
-
-[] indicates optional input (order unimportant)
-{} indicates required input (order unimportant)
-
-This script automates the creation  of three-dimensional PCoA plots to be visualized with Emperor using Google Chrome.
-
-Example usage: 
-Print help message and exit
- make_emperor.py -h
-
-...
-</code></pre>
-        </p>
-      <hr>
-
-      <div class="footer">
-        <a href="https://github.com/qiime/emperor/network/members">
-          <p align="center">© The Emperor Development Team</p>
-        </a>
-      </div>
-
-    </div> <!-- /container -->
-
-    <!-- Le javascript
-    ================================================== -->
-    <!-- Placed at the end of the document so the pages load faster -->
-    <script src="bootstrap/js/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap-transition.js"></script>
-    <script src="bootstrap/js/bootstrap-alert.js"></script>
-    <script src="bootstrap/js/bootstrap-modal.js"></script>
-    <script src="bootstrap/js/bootstrap-dropdown.js"></script>
-    <script src="bootstrap/js/bootstrap-scrollspy.js"></script>
-    <script src="bootstrap/js/bootstrap-tab.js"></script>
-    <script src="bootstrap/js/bootstrap-tooltip.js"></script>
-    <script src="bootstrap/js/bootstrap-popover.js"></script>
-    <script src="bootstrap/js/bootstrap-button.js"></script>
-    <script src="bootstrap/js/bootstrap-collapse.js"></script>
-    <script src="bootstrap/js/bootstrap-carousel.js"></script>
-    <script src="bootstrap/js/bootstrap-typeahead.js"></script>
-
-  </body>
-</html>
diff --git a/doc/jsdoc-config.json b/doc/jsdoc-config.json
new file mode 100644
index 0000000..0425105
--- /dev/null
+++ b/doc/jsdoc-config.json
@@ -0,0 +1,20 @@
+{
+    "tags": {
+        "allowUnknownTags": false,
+        "dictionaries": ["closure", "jsdoc"]
+    },
+    "source": {
+        "includePattern": ".+\\.js(doc)?$",
+        "excludePattern": "(^|\\/|\\\\)_"
+    },
+    "plugins": ["plugins/markdown",
+                "plugins/underscore"],
+    "templates": {
+        "cleverLinks": true,
+        "monospaceLinks": true
+    },
+    "opts": {
+        "recurse": true,
+        "pedantic": true
+    }
+}
diff --git a/doc/source/_static/copybutton.js b/doc/source/_static/copybutton.js
new file mode 100644
index 0000000..168a26c
--- /dev/null
+++ b/doc/source/_static/copybutton.js
@@ -0,0 +1,60 @@
+// originally taken from scikit-learn's Sphinx theme
+$(document).ready(function() {
+    /* Add a [>>>] button on the top-right corner of code samples to hide
+     * the >>> and ... prompts and the output and thus make the code
+     * copyable. 
+     * Note: This JS snippet was taken from the official python.org
+     * documentation site.*/
+    var div = $('.highlight-python .highlight,' +
+                '.highlight-python3 .highlight,' + 
+                '.highlight-pycon .highlight')
+    var pre = div.find('pre');
+
+    // get the styles from the current theme
+    pre.parent().parent().css('position', 'relative');
+    var hide_text = 'Hide the prompts and output';
+    var show_text = 'Show the prompts and output';
+    var border_width = pre.css('border-top-width');
+    var border_style = pre.css('border-top-style');
+    var border_color = pre.css('border-top-color');
+    var button_styles = {
+        'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0',
+        'border-color': border_color, 'border-style': border_style,
+        'border-width': border_width, 'color': border_color, 'text-size': '75%',
+        'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em'
+    }
+
+    // create and add the button to all the code blocks that contain >>>
+    div.each(function(index) {
+        var jthis = $(this);
+        if (jthis.find('.gp').length > 0) {
+            var button = $('<span class="copybutton">>>></span>');
+            button.css(button_styles)
+            button.attr('title', hide_text);
+            jthis.prepend(button);
+        }
+        // tracebacks (.gt) contain bare text elements that need to be
+        // wrapped in a span to work with .nextUntil() (see later)
+        jthis.find('pre:has(.gt)').contents().filter(function() {
+            return ((this.nodeType == 3) && (this.data.trim().length > 0));
+        }).wrap('<span>');
+    });
+
+    // define the behavior of the button when it's clicked
+    $('.copybutton').toggle(
+        function() {
+            var button = $(this);
+            button.parent().find('.go, .gp, .gt').hide();
+            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
+            button.css('text-decoration', 'line-through');
+            button.attr('title', show_text);
+        },
+        function() {
+            var button = $(this);
+            button.parent().find('.go, .gp, .gt').show();
+            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
+            button.css('text-decoration', 'none');
+            button.attr('title', hide_text);
+        });
+});
+
diff --git a/doc/source/_static/style.css b/doc/source/_static/style.css
new file mode 100644
index 0000000..f015e5b
--- /dev/null
+++ b/doc/source/_static/style.css
@@ -0,0 +1,38 @@
+blockquote {
+    font-size: 14px !important;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+    background:#E6E6E6;
+    border-color: black;
+    color: black;
+}
+
+div.admonition a {
+    color: #27A4F2; 
+}
+
+div.admonition dt {
+    font-weight: bold;
+    font-family: "Courier New";
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
diff --git a/doc/source/_templates/autosummary/attribute.rst b/doc/source/_templates/autosummary/attribute.rst
new file mode 100644
index 0000000..6a37ff0
--- /dev/null
+++ b/doc/source/_templates/autosummary/attribute.rst
@@ -0,0 +1,9 @@
+:orphan:
+
+{{ fullname }}
+{{ underline }}
+
+.. currentmodule:: {{ module }}
+
+.. autoattribute:: {{ objname }}
+
diff --git a/doc/source/_templates/autosummary/class.rst b/doc/source/_templates/autosummary/class.rst
new file mode 100644
index 0000000..daa8ff7
--- /dev/null
+++ b/doc/source/_templates/autosummary/class.rst
@@ -0,0 +1,27 @@
+{% extends "!autosummary/class.rst" %}
+
+{# Taken and modified from scipy's sphinx documentation setup (https://github.com/scipy/scipy/blob/master/doc/source/_templates/autosummary/class.rst). #}
+
+{% block methods %}
+{% if methods %}
+   .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages.
+      .. autosummary::
+         :toctree:
+      {% for item in all_methods %}
+         {{ name }}.{{ item }}
+      {%- endfor %}
+{% endif %}
+{% endblock %}
+
+{% block attributes %}
+{% if attributes %}
+   .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages.
+      .. autosummary::
+         :toctree:
+      {% for item in all_attributes %}
+         {%- if not item.startswith('_') %}
+         {{ name }}.{{ item }}
+         {%- endif -%}
+      {%- endfor %}
+{% endif %}
+{% endblock %}
diff --git a/doc/source/_templates/autosummary/method.rst b/doc/source/_templates/autosummary/method.rst
new file mode 100644
index 0000000..db18a82
--- /dev/null
+++ b/doc/source/_templates/autosummary/method.rst
@@ -0,0 +1,9 @@
+:orphan:
+
+{{ fullname }}
+{{ underline }}
+
+.. currentmodule:: {{ module }}
+
+.. automethod:: {{ objname }}
+
diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html
new file mode 100644
index 0000000..3495931
--- /dev/null
+++ b/doc/source/_templates/layout.html
@@ -0,0 +1,26 @@
+{% extends "!layout.html" %}
+
+{# Taken and modified from sphinx-bootstrap-theme demo site
+   (https://github.com/ryan-roemer/sphinx-bootstrap-theme/blob/master/demo/source/_templates/layout.html). #}
+
+{# Add github banner (from: https://github.com/blog/273-github-ribbons). #}
+{% block header %}
+  {{ super() }}
+  <a href="https://github.com/biocore/emperor"
+     class="visible-desktop hidden-xs"><img
+    id="gh-banner"
+    style="position: absolute; top: 50px; right: 0; border: 0;"
+    src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"
+    alt="Fork me on GitHub"></a>
+  <script>
+    // Adjust banner height.
+    $(function () {
+      var navHeight = $(".navbar .container").css("height");
+      $("#gh-banner").css("top", navHeight);
+    });
+  </script>
+{% endblock %}
+
+{% block footer %}
+  {{ super() }}
+{% endblock %}
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..fe5897e
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,282 @@
+# -*- coding: utf-8 -*-
+#
+# Emperor documentation build configuration file, created by
+# sphinx-quickstart on Sat Sep 13 10:33:08 2014.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+import glob
+
+import sphinx_bootstrap_theme
+
+# NOTE: parts of this file were taken from scipy's doc/source/conf.py. See
+# biom-format/licenses/scipy.txt for scipy's license.
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('sphinxext/numpydoc/'))
+
+# -- Options for autosummary ----------------------------------------------
+autosummary_generate = glob.glob('*.rst') + glob.glob('source/*.rst')
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.autodoc',
+              'sphinx.ext.imgmath',
+              'numpydoc',
+              'sphinx.ext.coverage',
+              'sphinx.ext.doctest',
+              'sphinx.ext.autosummary'
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Emperor'
+copyright = u'2014, Emperor Development Team'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.0.0beta5'
+
+# The full version, including alpha/beta/rc tags.
+release = '1.0.0beta5'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['build', '_templates/autosummary/*.rst', 'sphinxext']
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'bootstrap'
+html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+    # Navigation bar title. (Default: ``project`` value)
+
+    # Render the next and previous page links in navbar. (Default: true)
+    'navbar_sidebarrel': False,
+
+    # Bootswatch (http://bootswatch.com/) theme.
+    #
+    # Options are nothing with "" (default) or the name of a valid theme
+    # such as "amelia" or "cosmo".
+    'bootswatch_theme': 'yeti',
+
+    # Location of link to source.
+    # Options are "nav" (default), "footer" or anything else to exclude.
+    'source_link_position': False
+}
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Emperordoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+  ('index', 'Emperor.tex', u'Emperor Documentation',
+   u'Emperor Development Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'emperor', u'Emperor Documentation',
+     [u'Emperor Development Team'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'Emperor', u'Emperor Documentation',
+   u'Emperor Development Team', 'Emperor', 'A tool to visualize '
+   'high-dimensional microbial datasets',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+# Add the 'copybutton' javascript, to hide/show the prompt in code
+# examples, originally taken from scikit-learn's doc/conf.py
+def setup(app):
+    app.add_javascript('copybutton.js')
+    app.add_stylesheet('style.css')
diff --git a/doc/source/emperor_objects.rst b/doc/source/emperor_objects.rst
new file mode 100644
index 0000000..3fe81dd
--- /dev/null
+++ b/doc/source/emperor_objects.rst
@@ -0,0 +1,4 @@
+Emperor's public API
+====================
+
+.. automodule:: emperor
diff --git a/doc/source/formats.rst b/doc/source/formats.rst
new file mode 100644
index 0000000..0637734
--- /dev/null
+++ b/doc/source/formats.rst
@@ -0,0 +1,65 @@
+.. _formats:
+
+.. index:: formats
+
+File Formats
+============
+
+Emperor uses two main files as inputs, a mapping file and a coordinates file,
+here we will describe their structure.
+
+Mapping File
+^^^^^^^^^^^^
+
+A mapping file refers to the additional information collected about your
+samples, some common examples are body site, collection time, pH, latitude,
+longitude, etc. This information is used by Emperor to color and modify visual
+aspects of your plot in a systematic way.
+
+Mapping files should conform to the format as described by `QIIME
+<http://qiime.org/documentation/file_formats.html#metadata-mapping-files>`_.
+**Note** that the only required column is `SampleID`, if this column is not
+present the file will not be parsed correctly and the script will bring up an
+error.
+
+Coordinates File
+^^^^^^^^^^^^^^^^
+
+Coordinates files describe the position in which each of the samples should be
+placed in space, as of version `0.9.4-dev` there are two different file
+formats that are accepted by Emperor:
+
+**Classic Format**
+
+This format is tab-delimited and must include the following information (
+versions of QIIME <= 1.8.0 generate this file when you execute
+`principal_coordinates.py`):
+
+- The first line is the header for each of the dimensions.
+- For each of the samples in your dataset you'll find a line with a sample
+  identifier and its value at each dimension. If you have 7 samples you should
+  expect to see 7 lines with coordinates spanning through 7 dimensions.
+- Two empty lines.
+- A line with an eigenvalue for each dimension.
+- A line with the percentages of variation explained at each dimension.
+
+See the example below that presents a dataset where 5 samples were included.
+
+.. code-block:: none
+
+    pc vector number	1	2	3	4	5
+    PC.636	0.333514620475	0.081687	0.25081	0.103746	2.50106743521e-09
+    PC.635	0.258145479886	-0.22437	-0.25446	-0.0290044	2.50106743521e-09
+    PC.356	-0.270663791669	-0.23983	0.18965	-0.118931	2.50106743521e-09
+    PC.481	-0.0437436047686	0.30751	-0.077078	-0.20627	2.50106743521e-09
+    PC.354	-0.277252703922	0.074945	-0.10898	0.245681	2.50106743521e-09
+
+
+    eigvals	0.329912543767	0.2147172	0.1815366	0.1261003	-3.127915774e-17
+    % variation explained	38.68853	25.18276	21.2717	14.85772	3.667478e-15
+
+**scikit-bio Ordination Results**
+
+Emperor is also capable of parsing files generated by scikit-bio's
+`OrdinationResults <http://scikit-bio.org/docs/latest/generated/skbio.io.ordination.html>`_
+class.
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..86b74fb
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,38 @@
+.. Emperor documentation master file, created by
+   sphinx-quickstart on Sat Sep 13 10:33:08 2014.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Emperor's Documentation
+=======================
+
+Emperor is an interactive next generation tool for the analysis, visualization
+and understanding of high throughput microbial ecology datasets.
+
+The :ref:`genindex` lists the contents of this documentation.
+
+.. toctree::
+   :maxdepth: 4
+
+   emperor_objects
+
+Format Description:
+===================
+
+.. toctree::
+   :maxdepth: 2
+
+   formats
+
+
+Citing Emperor
+==============
+
+Remember to cite Emperor if you use it in any published research, please
+include the following citation:
+
+.. note::
+	**EMPeror: a tool for visualizing high-throughput microbial community data**. Vazquez-Baeza Y, Pirrung M, Gonzalez A, Knight R. Gigascience. 2013 Nov 26;2(1):16.
+
+
+You can find the `Emperor paper here <http://www.gigasciencejournal.com/content/2/1/16/>`_, and the data presented in this paper can be found `here <http://gigadb.org/dataset/100068>`_.
diff --git a/doc/source/sphinxext/numpydoc/LICENSE.txt b/doc/source/sphinxext/numpydoc/LICENSE.txt
new file mode 100644
index 0000000..b15c699
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/LICENSE.txt
@@ -0,0 +1,94 @@
+-------------------------------------------------------------------------------
+    The files
+    - numpydoc.py
+    - docscrape.py
+    - docscrape_sphinx.py
+    - phantom_import.py
+    have the following license:
+
+Copyright (C) 2008 Stefan van der Walt <stefan at mentat.za.net>, Pauli Virtanen <pav at iki.fi>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------------------
+    The files
+    - compiler_unparse.py
+    - comment_eater.py
+    - traitsdoc.py
+    have the following license:
+
+This software is OSI Certified Open Source Software.
+OSI Certified is a certification mark of the Open Source Initiative.
+
+Copyright (c) 2006, Enthought, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Enthought, Inc. nor the names of its contributors may
+   be used to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+-------------------------------------------------------------------------------
+    The file
+    - plot_directive.py
+    originates from Matplotlib (http://matplotlib.sf.net/) which has
+    the following license:
+
+Copyright (c) 2002-2008 John D. Hunter; All Rights Reserved.
+
+1. This LICENSE AGREEMENT is between John D. Hunter (“JDH”), and the Individual or Organization (“Licensee”) accessing and otherwise using matplotlib software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, JDH hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use matplotlib 0.98.3 alone or in any derivative version, provided, however, that JDH’s License Agreement and JDH’s notice of copyright, i.e., “Copyright (c) 2002-2008 John D. Hunter; All Rights Reserved” are retained in matplotlib 0.98 [...]
+
+3. In the event Licensee prepares a derivative work that is based on or incorporates matplotlib 0.98.3 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to matplotlib 0.98.3.
+
+4. JDH is making matplotlib 0.98.3 available to Licensee on an “AS IS” basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 0.98.3 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 0.98.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING MATPLOTLIB 0.98.3, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between JDH and Licensee. This License Agreement does not grant permission to use JDH trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using matplotlib 0.98.3, Licensee agrees to be bound by the terms and conditions of this License Agreement.
+
diff --git a/doc/source/sphinxext/numpydoc/README.rst b/doc/source/sphinxext/numpydoc/README.rst
new file mode 100644
index 0000000..0c40af1
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/README.rst
@@ -0,0 +1,54 @@
+.. image:: https://travis-ci.org/numpy/numpydoc.png?branch=master
+   :target: https://travis-ci.org/numpy/numpydoc/
+
+=====================================
+numpydoc -- Numpy's Sphinx extensions
+=====================================
+
+Numpy's documentation uses several custom extensions to Sphinx.  These
+are shipped in this ``numpydoc`` package, in case you want to make use
+of them in third-party projects.
+
+The following extensions are available:
+
+  - ``numpydoc``: support for the Numpy docstring format in Sphinx, and add
+    the code description directives ``np:function``, ``np-c:function``, etc.
+    that support the Numpy docstring syntax.
+
+  - ``numpydoc.traitsdoc``: For gathering documentation about Traits attributes.
+
+  - ``numpydoc.plot_directive``: Adaptation of Matplotlib's ``plot::``
+    directive. Note that this implementation may still undergo severe
+    changes or eventually be deprecated.
+
+
+numpydoc
+========
+
+Numpydoc inserts a hook into Sphinx's autodoc that converts docstrings
+following the Numpy/Scipy format to a form palatable to Sphinx.
+
+Options
+-------
+
+The following options can be set in conf.py:
+
+- numpydoc_use_plots: bool
+
+  Whether to produce ``plot::`` directives for Examples sections that
+  contain ``import matplotlib``.
+
+- numpydoc_show_class_members: bool
+
+  Whether to show all members of a class in the Methods and Attributes
+  sections automatically.
+
+- numpydoc_class_members_toctree: bool
+
+  Whether to create a Sphinx table of contents for the lists of class
+  methods and attributes. If a table of contents is made, Sphinx expects
+  each entry to have a separate page.
+
+- numpydoc_edit_link: bool  (DEPRECATED -- edit your HTML template instead)
+
+  Whether to insert an edit link after docstrings.
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/__init__.py b/doc/source/sphinxext/numpydoc/numpydoc/__init__.py
new file mode 100644
index 0000000..0fce2cf
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/__init__.py
@@ -0,0 +1,3 @@
+from __future__ import division, absolute_import, print_function
+
+from .numpydoc import setup
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/comment_eater.py b/doc/source/sphinxext/numpydoc/numpydoc/comment_eater.py
new file mode 100644
index 0000000..8cddd33
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/comment_eater.py
@@ -0,0 +1,169 @@
+from __future__ import division, absolute_import, print_function
+
+import sys
+if sys.version_info[0] >= 3:
+    from io import StringIO
+else:
+    from io import StringIO
+
+import compiler
+import inspect
+import textwrap
+import tokenize
+
+from .compiler_unparse import unparse
+
+
+class Comment(object):
+    """ A comment block.
+    """
+    is_comment = True
+    def __init__(self, start_lineno, end_lineno, text):
+        # int : The first line number in the block. 1-indexed.
+        self.start_lineno = start_lineno
+        # int : The last line number. Inclusive!
+        self.end_lineno = end_lineno
+        # str : The text block including '#' character but not any leading spaces.
+        self.text = text
+
+    def add(self, string, start, end, line):
+        """ Add a new comment line.
+        """
+        self.start_lineno = min(self.start_lineno, start[0])
+        self.end_lineno = max(self.end_lineno, end[0])
+        self.text += string
+
+    def __repr__(self):
+        return '%s(%r, %r, %r)' % (self.__class__.__name__, self.start_lineno,
+            self.end_lineno, self.text)
+
+
+class NonComment(object):
+    """ A non-comment block of code.
+    """
+    is_comment = False
+    def __init__(self, start_lineno, end_lineno):
+        self.start_lineno = start_lineno
+        self.end_lineno = end_lineno
+
+    def add(self, string, start, end, line):
+        """ Add lines to the block.
+        """
+        if string.strip():
+            # Only add if not entirely whitespace.
+            self.start_lineno = min(self.start_lineno, start[0])
+            self.end_lineno = max(self.end_lineno, end[0])
+
+    def __repr__(self):
+        return '%s(%r, %r)' % (self.__class__.__name__, self.start_lineno,
+            self.end_lineno)
+
+
+class CommentBlocker(object):
+    """ Pull out contiguous comment blocks.
+    """
+    def __init__(self):
+        # Start with a dummy.
+        self.current_block = NonComment(0, 0)
+
+        # All of the blocks seen so far.
+        self.blocks = []
+
+        # The index mapping lines of code to their associated comment blocks.
+        self.index = {}
+
+    def process_file(self, file):
+        """ Process a file object.
+        """
+        if sys.version_info[0] >= 3:
+            nxt = file.__next__
+        else:
+            nxt = file.next
+        for token in tokenize.generate_tokens(nxt):
+            self.process_token(*token)
+        self.make_index()
+
+    def process_token(self, kind, string, start, end, line):
+        """ Process a single token.
+        """
+        if self.current_block.is_comment:
+            if kind == tokenize.COMMENT:
+                self.current_block.add(string, start, end, line)
+            else:
+                self.new_noncomment(start[0], end[0])
+        else:
+            if kind == tokenize.COMMENT:
+                self.new_comment(string, start, end, line)
+            else:
+                self.current_block.add(string, start, end, line)
+
+    def new_noncomment(self, start_lineno, end_lineno):
+        """ We are transitioning from a noncomment to a comment.
+        """
+        block = NonComment(start_lineno, end_lineno)
+        self.blocks.append(block)
+        self.current_block = block
+
+    def new_comment(self, string, start, end, line):
+        """ Possibly add a new comment.
+
+        Only adds a new comment if this comment is the only thing on the line.
+        Otherwise, it extends the noncomment block.
+        """
+        prefix = line[:start[1]]
+        if prefix.strip():
+            # Oops! Trailing comment, not a comment block.
+            self.current_block.add(string, start, end, line)
+        else:
+            # A comment block.
+            block = Comment(start[0], end[0], string)
+            self.blocks.append(block)
+            self.current_block = block
+
+    def make_index(self):
+        """ Make the index mapping lines of actual code to their associated
+        prefix comments.
+        """
+        for prev, block in zip(self.blocks[:-1], self.blocks[1:]):
+            if not block.is_comment:
+                self.index[block.start_lineno] = prev
+
+    def search_for_comment(self, lineno, default=None):
+        """ Find the comment block just before the given line number.
+
+        Returns None (or the specified default) if there is no such block.
+        """
+        if not self.index:
+            self.make_index()
+        block = self.index.get(lineno, None)
+        text = getattr(block, 'text', default)
+        return text
+
+
+def strip_comment_marker(text):
+    """ Strip # markers at the front of a block of comment text.
+    """
+    lines = []
+    for line in text.splitlines():
+        lines.append(line.lstrip('#'))
+    text = textwrap.dedent('\n'.join(lines))
+    return text
+
+
+def get_class_traits(klass):
+    """ Yield all of the documentation for trait definitions on a class object.
+    """
+    # FIXME: gracefully handle errors here or in the caller?
+    source = inspect.getsource(klass)
+    cb = CommentBlocker()
+    cb.process_file(StringIO(source))
+    mod_ast = compiler.parse(source)
+    class_ast = mod_ast.node.nodes[0]
+    for node in class_ast.code.nodes:
+        # FIXME: handle other kinds of assignments?
+        if isinstance(node, compiler.ast.Assign):
+            name = node.nodes[0].name
+            rhs = unparse(node.expr).strip()
+            doc = strip_comment_marker(cb.search_for_comment(node.lineno, default=''))
+            yield name, rhs, doc
+
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/compiler_unparse.py b/doc/source/sphinxext/numpydoc/numpydoc/compiler_unparse.py
new file mode 100644
index 0000000..8933a83
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/compiler_unparse.py
@@ -0,0 +1,865 @@
+""" Turn compiler.ast structures back into executable python code.
+
+    The unparse method takes a compiler.ast tree and transforms it back into
+    valid python code.  It is incomplete and currently only works for
+    import statements, function calls, function definitions, assignments, and
+    basic expressions.
+
+    Inspired by python-2.5-svn/Demo/parser/unparse.py
+
+    fixme: We may want to move to using _ast trees because the compiler for
+           them is about 6 times faster than compiler.compile.
+"""
+from __future__ import division, absolute_import, print_function
+
+import sys
+from compiler.ast import Const, Name, Tuple, Div, Mul, Sub, Add
+
+if sys.version_info[0] >= 3:
+    from io import StringIO
+else:
+    from StringIO import StringIO
+
+def unparse(ast, single_line_functions=False):
+    s = StringIO()
+    UnparseCompilerAst(ast, s, single_line_functions)
+    return s.getvalue().lstrip()
+
+op_precedence = { 'compiler.ast.Power':3, 'compiler.ast.Mul':2, 'compiler.ast.Div':2,
+                  'compiler.ast.Add':1, 'compiler.ast.Sub':1 }
+
+class UnparseCompilerAst:
+    """ Methods in this class recursively traverse an AST and
+        output source code for the abstract syntax; original formatting
+        is disregarged.
+    """
+
+    #########################################################################
+    # object interface.
+    #########################################################################
+
+    def __init__(self, tree, file = sys.stdout, single_line_functions=False):
+        """ Unparser(tree, file=sys.stdout) -> None.
+
+            Print the source for tree to file.
+        """
+        self.f = file
+        self._single_func = single_line_functions
+        self._do_indent = True
+        self._indent = 0
+        self._dispatch(tree)
+        self._write("\n")
+        self.f.flush()
+
+    #########################################################################
+    # Unparser private interface.
+    #########################################################################
+
+    ### format, output, and dispatch methods ################################
+
+    def _fill(self, text = ""):
+        "Indent a piece of text, according to the current indentation level"
+        if self._do_indent:
+            self._write("\n"+"    "*self._indent + text)
+        else:
+            self._write(text)
+
+    def _write(self, text):
+        "Append a piece of text to the current line."
+        self.f.write(text)
+
+    def _enter(self):
+        "Print ':', and increase the indentation."
+        self._write(": ")
+        self._indent += 1
+
+    def _leave(self):
+        "Decrease the indentation level."
+        self._indent -= 1
+
+    def _dispatch(self, tree):
+        "_dispatcher function, _dispatching tree type T to method _T."
+        if isinstance(tree, list):
+            for t in tree:
+                self._dispatch(t)
+            return
+        meth = getattr(self, "_"+tree.__class__.__name__)
+        if tree.__class__.__name__ == 'NoneType' and not self._do_indent:
+            return
+        meth(tree)
+
+
+    #########################################################################
+    # compiler.ast unparsing methods.
+    #
+    # There should be one method per concrete grammar type. They are
+    # organized in alphabetical order.
+    #########################################################################
+
+    def _Add(self, t):
+        self.__binary_op(t, '+')
+
+    def _And(self, t):
+        self._write(" (")
+        for i, node in enumerate(t.nodes):
+            self._dispatch(node)
+            if i != len(t.nodes)-1:
+                self._write(") and (")
+        self._write(")")
+
+    def _AssAttr(self, t):
+        """ Handle assigning an attribute of an object
+        """
+        self._dispatch(t.expr)
+        self._write('.'+t.attrname)
+
+    def _Assign(self, t):
+        """ Expression Assignment such as "a = 1".
+
+            This only handles assignment in expressions.  Keyword assignment
+            is handled separately.
+        """
+        self._fill()
+        for target in t.nodes:
+            self._dispatch(target)
+            self._write(" = ")
+        self._dispatch(t.expr)
+        if not self._do_indent:
+            self._write('; ')
+
+    def _AssName(self, t):
+        """ Name on left hand side of expression.
+
+            Treat just like a name on the right side of an expression.
+        """
+        self._Name(t)
+
+    def _AssTuple(self, t):
+        """ Tuple on left hand side of an expression.
+        """
+
+        # _write each elements, separated by a comma.
+        for element in t.nodes[:-1]:
+            self._dispatch(element)
+            self._write(", ")
+
+        # Handle the last one without writing comma
+        last_element = t.nodes[-1]
+        self._dispatch(last_element)
+
+    def _AugAssign(self, t):
+        """ +=,-=,*=,/=,**=, etc. operations
+        """
+
+        self._fill()
+        self._dispatch(t.node)
+        self._write(' '+t.op+' ')
+        self._dispatch(t.expr)
+        if not self._do_indent:
+            self._write(';')
+
+    def _Bitand(self, t):
+        """ Bit and operation.
+        """
+
+        for i, node in enumerate(t.nodes):
+            self._write("(")
+            self._dispatch(node)
+            self._write(")")
+            if i != len(t.nodes)-1:
+                self._write(" & ")
+
+    def _Bitor(self, t):
+        """ Bit or operation
+        """
+
+        for i, node in enumerate(t.nodes):
+            self._write("(")
+            self._dispatch(node)
+            self._write(")")
+            if i != len(t.nodes)-1:
+                self._write(" | ")
+
+    def _CallFunc(self, t):
+        """ Function call.
+        """
+        self._dispatch(t.node)
+        self._write("(")
+        comma = False
+        for e in t.args:
+            if comma: self._write(", ")
+            else: comma = True
+            self._dispatch(e)
+        if t.star_args:
+            if comma: self._write(", ")
+            else: comma = True
+            self._write("*")
+            self._dispatch(t.star_args)
+        if t.dstar_args:
+            if comma: self._write(", ")
+            else: comma = True
+            self._write("**")
+            self._dispatch(t.dstar_args)
+        self._write(")")
+
+    def _Compare(self, t):
+        self._dispatch(t.expr)
+        for op, expr in t.ops:
+            self._write(" " + op + " ")
+            self._dispatch(expr)
+
+    def _Const(self, t):
+        """ A constant value such as an integer value, 3, or a string, "hello".
+        """
+        self._dispatch(t.value)
+
+    def _Decorators(self, t):
+        """ Handle function decorators (eg. @has_units)
+        """
+        for node in t.nodes:
+            self._dispatch(node)
+
+    def _Dict(self, t):
+        self._write("{")
+        for  i, (k, v) in enumerate(t.items):
+            self._dispatch(k)
+            self._write(": ")
+            self._dispatch(v)
+            if i < len(t.items)-1:
+                self._write(", ")
+        self._write("}")
+
+    def _Discard(self, t):
+        """ Node for when return value is ignored such as in "foo(a)".
+        """
+        self._fill()
+        self._dispatch(t.expr)
+
+    def _Div(self, t):
+        self.__binary_op(t, '/')
+
+    def _Ellipsis(self, t):
+        self._write("...")
+
+    def _From(self, t):
+        """ Handle "from xyz import foo, bar as baz".
+        """
+        # fixme: Are From and ImportFrom handled differently?
+        self._fill("from ")
+        self._write(t.modname)
+        self._write(" import ")
+        for i, (name,asname) in enumerate(t.names):
+            if i != 0:
+                self._write(", ")
+            self._write(name)
+            if asname is not None:
+                self._write(" as "+asname)
+
+    def _Function(self, t):
+        """ Handle function definitions
+        """
+        if t.decorators is not None:
+            self._fill("@")
+            self._dispatch(t.decorators)
+        self._fill("def "+t.name + "(")
+        defaults = [None] * (len(t.argnames) - len(t.defaults)) + list(t.defaults)
+        for i, arg in enumerate(zip(t.argnames, defaults)):
+            self._write(arg[0])
+            if arg[1] is not None:
+                self._write('=')
+                self._dispatch(arg[1])
+            if i < len(t.argnames)-1:
+                self._write(', ')
+        self._write(")")
+        if self._single_func:
+            self._do_indent = False
+        self._enter()
+        self._dispatch(t.code)
+        self._leave()
+        self._do_indent = True
+
+    def _Getattr(self, t):
+        """ Handle getting an attribute of an object
+        """
+        if isinstance(t.expr, (Div, Mul, Sub, Add)):
+            self._write('(')
+            self._dispatch(t.expr)
+            self._write(')')
+        else:
+            self._dispatch(t.expr)
+            
+        self._write('.'+t.attrname)
+        
+    def _If(self, t):
+        self._fill()
+        
+        for i, (compare,code) in enumerate(t.tests):
+            if i == 0:
+                self._write("if ")
+            else:
+                self._write("elif ")
+            self._dispatch(compare)
+            self._enter()
+            self._fill()
+            self._dispatch(code)
+            self._leave()
+            self._write("\n")
+
+        if t.else_ is not None:
+            self._write("else")
+            self._enter()
+            self._fill()
+            self._dispatch(t.else_)
+            self._leave()
+            self._write("\n")
+            
+    def _IfExp(self, t):
+        self._dispatch(t.then)
+        self._write(" if ")
+        self._dispatch(t.test)
+
+        if t.else_ is not None:
+            self._write(" else (")
+            self._dispatch(t.else_)
+            self._write(")")
+
+    def _Import(self, t):
+        """ Handle "import xyz.foo".
+        """
+        self._fill("import ")
+        
+        for i, (name,asname) in enumerate(t.names):
+            if i != 0:
+                self._write(", ")
+            self._write(name)
+            if asname is not None:
+                self._write(" as "+asname)
+
+    def _Keyword(self, t):
+        """ Keyword value assignment within function calls and definitions.
+        """
+        self._write(t.name)
+        self._write("=")
+        self._dispatch(t.expr)
+        
+    def _List(self, t):
+        self._write("[")
+        for  i,node in enumerate(t.nodes):
+            self._dispatch(node)
+            if i < len(t.nodes)-1:
+                self._write(", ")
+        self._write("]")
+
+    def _Module(self, t):
+        if t.doc is not None:
+            self._dispatch(t.doc)
+        self._dispatch(t.node)
+
+    def _Mul(self, t):
+        self.__binary_op(t, '*')
+
+    def _Name(self, t):
+        self._write(t.name)
+
+    def _NoneType(self, t):
+        self._write("None")
+        
+    def _Not(self, t):
+        self._write('not (')
+        self._dispatch(t.expr)
+        self._write(')')
+        
+    def _Or(self, t):
+        self._write(" (")
+        for i, node in enumerate(t.nodes):
+            self._dispatch(node)
+            if i != len(t.nodes)-1:
+                self._write(") or (")
+        self._write(")")
+                
+    def _Pass(self, t):
+        self._write("pass\n")
+
+    def _Printnl(self, t):
+        self._fill("print ")
+        if t.dest:
+            self._write(">> ")
+            self._dispatch(t.dest)
+            self._write(", ")
+        comma = False
+        for node in t.nodes:
+            if comma: self._write(', ')
+            else: comma = True
+            self._dispatch(node)
+
+    def _Power(self, t):
+        self.__binary_op(t, '**')
+
+    def _Return(self, t):
+        self._fill("return ")
+        if t.value:
+            if isinstance(t.value, Tuple):
+                text = ', '.join([ name.name for name in t.value.asList() ])
+                self._write(text)
+            else:
+                self._dispatch(t.value)
+            if not self._do_indent:
+                self._write('; ')
+
+    def _Slice(self, t):
+        self._dispatch(t.expr)
+        self._write("[")
+        if t.lower:
+            self._dispatch(t.lower)
+        self._write(":")
+        if t.upper:
+            self._dispatch(t.upper)
+        #if t.step:
+        #    self._write(":")
+        #    self._dispatch(t.step)
+        self._write("]")
+
+    def _Sliceobj(self, t):
+        for i, node in enumerate(t.nodes):
+            if i != 0:
+                self._write(":")
+            if not (isinstance(node, Const) and node.value is None):
+                self._dispatch(node)
+
+    def _Stmt(self, tree):
+        for node in tree.nodes:
+            self._dispatch(node)
+
+    def _Sub(self, t):
+        self.__binary_op(t, '-')
+
+    def _Subscript(self, t):
+        self._dispatch(t.expr)
+        self._write("[")
+        for i, value in enumerate(t.subs):
+            if i != 0:
+                self._write(",")
+            self._dispatch(value)
+        self._write("]")
+
+    def _TryExcept(self, t):
+        self._fill("try")
+        self._enter()
+        self._dispatch(t.body)
+        self._leave()
+
+        for handler in t.handlers:
+            self._fill('except ')
+            self._dispatch(handler[0])
+            if handler[1] is not None:
+                self._write(', ')
+                self._dispatch(handler[1])
+            self._enter()
+            self._dispatch(handler[2])
+            self._leave()
+            
+        if t.else_:
+            self._fill("else")
+            self._enter()
+            self._dispatch(t.else_)
+            self._leave()
+
+    def _Tuple(self, t):
+
+        if not t.nodes:
+            # Empty tuple.
+            self._write("()")
+        else:
+            self._write("(")
+
+            # _write each elements, separated by a comma.
+            for element in t.nodes[:-1]:
+                self._dispatch(element)
+                self._write(", ")
+
+            # Handle the last one without writing comma
+            last_element = t.nodes[-1]
+            self._dispatch(last_element)
+
+            self._write(")")
+            
+    def _UnaryAdd(self, t):
+        self._write("+")
+        self._dispatch(t.expr)
+        
+    def _UnarySub(self, t):
+        self._write("-")
+        self._dispatch(t.expr)        
+
+    def _With(self, t):
+        self._fill('with ')
+        self._dispatch(t.expr)
+        if t.vars:
+            self._write(' as ')
+            self._dispatch(t.vars.name)
+        self._enter()
+        self._dispatch(t.body)
+        self._leave()
+        self._write('\n')
+        
+    def _int(self, t):
+        self._write(repr(t))
+
+    def __binary_op(self, t, symbol):
+        # Check if parenthesis are needed on left side and then dispatch
+        has_paren = False
+        left_class = str(t.left.__class__)
+        if (left_class in op_precedence.keys() and
+            op_precedence[left_class] < op_precedence[str(t.__class__)]):
+            has_paren = True
+        if has_paren:
+            self._write('(')
+        self._dispatch(t.left)
+        if has_paren:
+            self._write(')')
+        # Write the appropriate symbol for operator
+        self._write(symbol)
+        # Check if parenthesis are needed on the right side and then dispatch
+        has_paren = False
+        right_class = str(t.right.__class__)
+        if (right_class in op_precedence.keys() and
+            op_precedence[right_class] < op_precedence[str(t.__class__)]):
+            has_paren = True
+        if has_paren:
+            self._write('(')
+        self._dispatch(t.right)
+        if has_paren:
+            self._write(')')
+
+    def _float(self, t):
+        # if t is 0.1, str(t)->'0.1' while repr(t)->'0.1000000000001'
+        # We prefer str here.
+        self._write(str(t))
+
+    def _str(self, t):
+        self._write(repr(t))
+        
+    def _tuple(self, t):
+        self._write(str(t))
+
+    #########################################################################
+    # These are the methods from the _ast modules unparse.
+    #
+    # As our needs to handle more advanced code increase, we may want to
+    # modify some of the methods below so that they work for compiler.ast.
+    #########################################################################
+
+#    # stmt
+#    def _Expr(self, tree):
+#        self._fill()
+#        self._dispatch(tree.value)
+#
+#    def _Import(self, t):
+#        self._fill("import ")
+#        first = True
+#        for a in t.names:
+#            if first:
+#                first = False
+#            else:
+#                self._write(", ")
+#            self._write(a.name)
+#            if a.asname:
+#                self._write(" as "+a.asname)
+#
+##    def _ImportFrom(self, t):
+##        self._fill("from ")
+##        self._write(t.module)
+##        self._write(" import ")
+##        for i, a in enumerate(t.names):
+##            if i == 0:
+##                self._write(", ")
+##            self._write(a.name)
+##            if a.asname:
+##                self._write(" as "+a.asname)
+##        # XXX(jpe) what is level for?
+##
+#
+#    def _Break(self, t):
+#        self._fill("break")
+#
+#    def _Continue(self, t):
+#        self._fill("continue")
+#
+#    def _Delete(self, t):
+#        self._fill("del ")
+#        self._dispatch(t.targets)
+#
+#    def _Assert(self, t):
+#        self._fill("assert ")
+#        self._dispatch(t.test)
+#        if t.msg:
+#            self._write(", ")
+#            self._dispatch(t.msg)
+#
+#    def _Exec(self, t):
+#        self._fill("exec ")
+#        self._dispatch(t.body)
+#        if t.globals:
+#            self._write(" in ")
+#            self._dispatch(t.globals)
+#        if t.locals:
+#            self._write(", ")
+#            self._dispatch(t.locals)
+#
+#    def _Print(self, t):
+#        self._fill("print ")
+#        do_comma = False
+#        if t.dest:
+#            self._write(">>")
+#            self._dispatch(t.dest)
+#            do_comma = True
+#        for e in t.values:
+#            if do_comma:self._write(", ")
+#            else:do_comma=True
+#            self._dispatch(e)
+#        if not t.nl:
+#            self._write(",")
+#
+#    def _Global(self, t):
+#        self._fill("global")
+#        for i, n in enumerate(t.names):
+#            if i != 0:
+#                self._write(",")
+#            self._write(" " + n)
+#
+#    def _Yield(self, t):
+#        self._fill("yield")
+#        if t.value:
+#            self._write(" (")
+#            self._dispatch(t.value)
+#            self._write(")")
+#
+#    def _Raise(self, t):
+#        self._fill('raise ')
+#        if t.type:
+#            self._dispatch(t.type)
+#        if t.inst:
+#            self._write(", ")
+#            self._dispatch(t.inst)
+#        if t.tback:
+#            self._write(", ")
+#            self._dispatch(t.tback)
+#
+#
+#    def _TryFinally(self, t):
+#        self._fill("try")
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#
+#        self._fill("finally")
+#        self._enter()
+#        self._dispatch(t.finalbody)
+#        self._leave()
+#
+#    def _excepthandler(self, t):
+#        self._fill("except ")
+#        if t.type:
+#            self._dispatch(t.type)
+#        if t.name:
+#            self._write(", ")
+#            self._dispatch(t.name)
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#
+#    def _ClassDef(self, t):
+#        self._write("\n")
+#        self._fill("class "+t.name)
+#        if t.bases:
+#            self._write("(")
+#            for a in t.bases:
+#                self._dispatch(a)
+#                self._write(", ")
+#            self._write(")")
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#
+#    def _FunctionDef(self, t):
+#        self._write("\n")
+#        for deco in t.decorators:
+#            self._fill("@")
+#            self._dispatch(deco)
+#        self._fill("def "+t.name + "(")
+#        self._dispatch(t.args)
+#        self._write(")")
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#
+#    def _For(self, t):
+#        self._fill("for ")
+#        self._dispatch(t.target)
+#        self._write(" in ")
+#        self._dispatch(t.iter)
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#        if t.orelse:
+#            self._fill("else")
+#            self._enter()
+#            self._dispatch(t.orelse)
+#            self._leave
+#
+#    def _While(self, t):
+#        self._fill("while ")
+#        self._dispatch(t.test)
+#        self._enter()
+#        self._dispatch(t.body)
+#        self._leave()
+#        if t.orelse:
+#            self._fill("else")
+#            self._enter()
+#            self._dispatch(t.orelse)
+#            self._leave
+#
+#    # expr
+#    def _Str(self, tree):
+#        self._write(repr(tree.s))
+##
+#    def _Repr(self, t):
+#        self._write("`")
+#        self._dispatch(t.value)
+#        self._write("`")
+#
+#    def _Num(self, t):
+#        self._write(repr(t.n))
+#
+#    def _ListComp(self, t):
+#        self._write("[")
+#        self._dispatch(t.elt)
+#        for gen in t.generators:
+#            self._dispatch(gen)
+#        self._write("]")
+#
+#    def _GeneratorExp(self, t):
+#        self._write("(")
+#        self._dispatch(t.elt)
+#        for gen in t.generators:
+#            self._dispatch(gen)
+#        self._write(")")
+#
+#    def _comprehension(self, t):
+#        self._write(" for ")
+#        self._dispatch(t.target)
+#        self._write(" in ")
+#        self._dispatch(t.iter)
+#        for if_clause in t.ifs:
+#            self._write(" if ")
+#            self._dispatch(if_clause)
+#
+#    def _IfExp(self, t):
+#        self._dispatch(t.body)
+#        self._write(" if ")
+#        self._dispatch(t.test)
+#        if t.orelse:
+#            self._write(" else ")
+#            self._dispatch(t.orelse)
+#
+#    unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
+#    def _UnaryOp(self, t):
+#        self._write(self.unop[t.op.__class__.__name__])
+#        self._write("(")
+#        self._dispatch(t.operand)
+#        self._write(")")
+#
+#    binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
+#                    "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
+#                    "FloorDiv":"//", "Pow": "**"}
+#    def _BinOp(self, t):
+#        self._write("(")
+#        self._dispatch(t.left)
+#        self._write(")" + self.binop[t.op.__class__.__name__] + "(")
+#        self._dispatch(t.right)
+#        self._write(")")
+#
+#    boolops = {_ast.And: 'and', _ast.Or: 'or'}
+#    def _BoolOp(self, t):
+#        self._write("(")
+#        self._dispatch(t.values[0])
+#        for v in t.values[1:]:
+#            self._write(" %s " % self.boolops[t.op.__class__])
+#            self._dispatch(v)
+#        self._write(")")
+#
+#    def _Attribute(self,t):
+#        self._dispatch(t.value)
+#        self._write(".")
+#        self._write(t.attr)
+#
+##    def _Call(self, t):
+##        self._dispatch(t.func)
+##        self._write("(")
+##        comma = False
+##        for e in t.args:
+##            if comma: self._write(", ")
+##            else: comma = True
+##            self._dispatch(e)
+##        for e in t.keywords:
+##            if comma: self._write(", ")
+##            else: comma = True
+##            self._dispatch(e)
+##        if t.starargs:
+##            if comma: self._write(", ")
+##            else: comma = True
+##            self._write("*")
+##            self._dispatch(t.starargs)
+##        if t.kwargs:
+##            if comma: self._write(", ")
+##            else: comma = True
+##            self._write("**")
+##            self._dispatch(t.kwargs)
+##        self._write(")")
+#
+#    # slice
+#    def _Index(self, t):
+#        self._dispatch(t.value)
+#
+#    def _ExtSlice(self, t):
+#        for i, d in enumerate(t.dims):
+#            if i != 0:
+#                self._write(': ')
+#            self._dispatch(d)
+#
+#    # others
+#    def _arguments(self, t):
+#        first = True
+#        nonDef = len(t.args)-len(t.defaults)
+#        for a in t.args[0:nonDef]:
+#            if first:first = False
+#            else: self._write(", ")
+#            self._dispatch(a)
+#        for a,d in zip(t.args[nonDef:], t.defaults):
+#            if first:first = False
+#            else: self._write(", ")
+#            self._dispatch(a),
+#            self._write("=")
+#            self._dispatch(d)
+#        if t.vararg:
+#            if first:first = False
+#            else: self._write(", ")
+#            self._write("*"+t.vararg)
+#        if t.kwarg:
+#            if first:first = False
+#            else: self._write(", ")
+#            self._write("**"+t.kwarg)
+#
+##    def _keyword(self, t):
+##        self._write(t.arg)
+##        self._write("=")
+##        self._dispatch(t.value)
+#
+#    def _Lambda(self, t):
+#        self._write("lambda ")
+#        self._dispatch(t.args)
+#        self._write(": ")
+#        self._dispatch(t.body)
+
+
+
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/docscrape.py b/doc/source/sphinxext/numpydoc/numpydoc/docscrape.py
new file mode 100644
index 0000000..b31d06d
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/docscrape.py
@@ -0,0 +1,525 @@
+"""Extract reference documentation from the NumPy source tree.
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import inspect
+import textwrap
+import re
+import pydoc
+from warnings import warn
+import collections
+
+
+class Reader(object):
+    """A line-based string reader.
+
+    """
+    def __init__(self, data):
+        """
+        Parameters
+        ----------
+        data : str
+           String with lines separated by '\n'.
+
+        """
+        if isinstance(data,list):
+            self._str = data
+        else:
+            self._str = data.split('\n') # store string as list of lines
+
+        self.reset()
+
+    def __getitem__(self, n):
+        return self._str[n]
+
+    def reset(self):
+        self._l = 0 # current line nr
+
+    def read(self):
+        if not self.eof():
+            out = self[self._l]
+            self._l += 1
+            return out
+        else:
+            return ''
+
+    def seek_next_non_empty_line(self):
+        for l in self[self._l:]:
+            if l.strip():
+                break
+            else:
+                self._l += 1
+
+    def eof(self):
+        return self._l >= len(self._str)
+
+    def read_to_condition(self, condition_func):
+        start = self._l
+        for line in self[start:]:
+            if condition_func(line):
+                return self[start:self._l]
+            self._l += 1
+            if self.eof():
+                return self[start:self._l+1]
+        return []
+
+    def read_to_next_empty_line(self):
+        self.seek_next_non_empty_line()
+        def is_empty(line):
+            return not line.strip()
+        return self.read_to_condition(is_empty)
+
+    def read_to_next_unindented_line(self):
+        def is_unindented(line):
+            return (line.strip() and (len(line.lstrip()) == len(line)))
+        return self.read_to_condition(is_unindented)
+
+    def peek(self,n=0):
+        if self._l + n < len(self._str):
+            return self[self._l + n]
+        else:
+            return ''
+
+    def is_empty(self):
+        return not ''.join(self._str).strip()
+
+
+class NumpyDocString(object):
+    def __init__(self, docstring, config={}):
+        docstring = textwrap.dedent(docstring).split('\n')
+
+        self._doc = Reader(docstring)
+        self._parsed_data = {
+            'Signature': '',
+            'Summary': [''],
+            'Extended Summary': [],
+            'Parameters': [],
+            'Returns': [],
+            'Raises': [],
+            'Warns': [],
+            'Other Parameters': [],
+            'Attributes': [],
+            'Methods': [],
+            'See Also': [],
+            'Notes': [],
+            'Warnings': [],
+            'References': '',
+            'Examples': '',
+            'index': {}
+            }
+
+        self._parse()
+
+    def __getitem__(self,key):
+        return self._parsed_data[key]
+
+    def __setitem__(self,key,val):
+        if key not in self._parsed_data:
+            warn("Unknown section %s" % key)
+        else:
+            self._parsed_data[key] = val
+
+    def _is_at_section(self):
+        self._doc.seek_next_non_empty_line()
+
+        if self._doc.eof():
+            return False
+
+        l1 = self._doc.peek().strip()  # e.g. Parameters
+
+        if l1.startswith('.. index::'):
+            return True
+
+        l2 = self._doc.peek(1).strip() #    ---------- or ==========
+        return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1))
+
+    def _strip(self,doc):
+        i = 0
+        j = 0
+        for i,line in enumerate(doc):
+            if line.strip(): break
+
+        for j,line in enumerate(doc[::-1]):
+            if line.strip(): break
+
+        return doc[i:len(doc)-j]
+
+    def _read_to_next_section(self):
+        section = self._doc.read_to_next_empty_line()
+
+        while not self._is_at_section() and not self._doc.eof():
+            if not self._doc.peek(-1).strip(): # previous line was empty
+                section += ['']
+
+            section += self._doc.read_to_next_empty_line()
+
+        return section
+
+    def _read_sections(self):
+        while not self._doc.eof():
+            data = self._read_to_next_section()
+            name = data[0].strip()
+
+            if name.startswith('..'): # index section
+                yield name, data[1:]
+            elif len(data) < 2:
+                yield StopIteration
+            else:
+                yield name, self._strip(data[2:])
+
+    def _parse_param_list(self,content):
+        r = Reader(content)
+        params = []
+        while not r.eof():
+            header = r.read().strip()
+            if ' : ' in header:
+                arg_name, arg_type = header.split(' : ')[:2]
+            else:
+                arg_name, arg_type = header, ''
+
+            desc = r.read_to_next_unindented_line()
+            desc = dedent_lines(desc)
+
+            params.append((arg_name,arg_type,desc))
+
+        return params
+
+
+    _name_rgx = re.compile(r"^\s*(:(?P<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
+                           r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X)
+    def _parse_see_also(self, content):
+        """
+        func_name : Descriptive text
+            continued text
+        another_func_name : Descriptive text
+        func_name1, func_name2, :meth:`func_name`, func_name3
+
+        """
+        items = []
+
+        def parse_item_name(text):
+            """Match ':role:`name`' or 'name'"""
+            m = self._name_rgx.match(text)
+            if m:
+                g = m.groups()
+                if g[1] is None:
+                    return g[3], None
+                else:
+                    return g[2], g[1]
+            raise ValueError("%s is not a item name" % text)
+
+        def push_item(name, rest):
+            if not name:
+                return
+            name, role = parse_item_name(name)
+            items.append((name, list(rest), role))
+            del rest[:]
+
+        current_func = None
+        rest = []
+
+        for line in content:
+            if not line.strip(): continue
+
+            m = self._name_rgx.match(line)
+            if m and line[m.end():].strip().startswith(':'):
+                push_item(current_func, rest)
+                current_func, line = line[:m.end()], line[m.end():]
+                rest = [line.split(':', 1)[1].strip()]
+                if not rest[0]:
+                    rest = []
+            elif not line.startswith(' '):
+                push_item(current_func, rest)
+                current_func = None
+                if ',' in line:
+                    for func in line.split(','):
+                        if func.strip():
+                            push_item(func, [])
+                elif line.strip():
+                    current_func = line
+            elif current_func is not None:
+                rest.append(line.strip())
+        push_item(current_func, rest)
+        return items
+
+    def _parse_index(self, section, content):
+        """
+        .. index: default
+           :refguide: something, else, and more
+
+        """
+        def strip_each_in(lst):
+            return [s.strip() for s in lst]
+
+        out = {}
+        section = section.split('::')
+        if len(section) > 1:
+            out['default'] = strip_each_in(section[1].split(','))[0]
+        for line in content:
+            line = line.split(':')
+            if len(line) > 2:
+                out[line[1]] = strip_each_in(line[2].split(','))
+        return out
+
+    def _parse_summary(self):
+        """Grab signature (if given) and summary"""
+        if self._is_at_section():
+            return
+
+        # If several signatures present, take the last one
+        while True:
+            summary = self._doc.read_to_next_empty_line()
+            summary_str = " ".join([s.strip() for s in summary]).strip()
+            if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str):
+                self['Signature'] = summary_str
+                if not self._is_at_section():
+                    continue
+            break
+
+        if summary is not None:
+            self['Summary'] = summary
+
+        if not self._is_at_section():
+            self['Extended Summary'] = self._read_to_next_section()
+
+    def _parse(self):
+        self._doc.reset()
+        self._parse_summary()
+
+        for (section,content) in self._read_sections():
+            if not section.startswith('..'):
+                section = ' '.join([s.capitalize() for s in section.split(' ')])
+            if section in ('Parameters', 'Returns', 'Raises', 'Warns',
+                           'Other Parameters', 'Attributes', 'Methods'):
+                self[section] = self._parse_param_list(content)
+            elif section.startswith('.. index::'):
+                self['index'] = self._parse_index(section, content)
+            elif section == 'See Also':
+                self['See Also'] = self._parse_see_also(content)
+            else:
+                self[section] = content
+
+    # string conversion routines
+
+    def _str_header(self, name, symbol='-'):
+        return [name, len(name)*symbol]
+
+    def _str_indent(self, doc, indent=4):
+        out = []
+        for line in doc:
+            out += [' '*indent + line]
+        return out
+
+    def _str_signature(self):
+        if self['Signature']:
+            return [self['Signature'].replace('*','\*')] + ['']
+        else:
+            return ['']
+
+    def _str_summary(self):
+        if self['Summary']:
+            return self['Summary'] + ['']
+        else:
+            return []
+
+    def _str_extended_summary(self):
+        if self['Extended Summary']:
+            return self['Extended Summary'] + ['']
+        else:
+            return []
+
+    def _str_param_list(self, name):
+        out = []
+        if self[name]:
+            out += self._str_header(name)
+            for param,param_type,desc in self[name]:
+                if param_type:
+                    out += ['%s : %s' % (param, param_type)]
+                else:
+                    out += [param]
+                out += self._str_indent(desc)
+            out += ['']
+        return out
+
+    def _str_section(self, name):
+        out = []
+        if self[name]:
+            out += self._str_header(name)
+            out += self[name]
+            out += ['']
+        return out
+
+    def _str_see_also(self, func_role):
+        if not self['See Also']: return []
+        out = []
+        out += self._str_header("See Also")
+        last_had_desc = True
+        for func, desc, role in self['See Also']:
+            if role:
+                link = ':%s:`%s`' % (role, func)
+            elif func_role:
+                link = ':%s:`%s`' % (func_role, func)
+            else:
+                link = "`%s`_" % func
+            if desc or last_had_desc:
+                out += ['']
+                out += [link]
+            else:
+                out[-1] += ", %s" % link
+            if desc:
+                out += self._str_indent([' '.join(desc)])
+                last_had_desc = True
+            else:
+                last_had_desc = False
+        out += ['']
+        return out
+
+    def _str_index(self):
+        idx = self['index']
+        out = []
+        out += ['.. index:: %s' % idx.get('default','')]
+        for section, references in idx.items():
+            if section == 'default':
+                continue
+            out += ['   :%s: %s' % (section, ', '.join(references))]
+        return out
+
+    def __str__(self, func_role=''):
+        out = []
+        out += self._str_signature()
+        out += self._str_summary()
+        out += self._str_extended_summary()
+        for param_list in ('Parameters', 'Returns', 'Other Parameters',
+                           'Raises', 'Warns'):
+            out += self._str_param_list(param_list)
+        out += self._str_section('Warnings')
+        out += self._str_see_also(func_role)
+        for s in ('Notes','References','Examples'):
+            out += self._str_section(s)
+        for param_list in ('Attributes', 'Methods'):
+            out += self._str_param_list(param_list)
+        out += self._str_index()
+        return '\n'.join(out)
+
+
+def indent(str,indent=4):
+    indent_str = ' '*indent
+    if str is None:
+        return indent_str
+    lines = str.split('\n')
+    return '\n'.join(indent_str + l for l in lines)
+
+def dedent_lines(lines):
+    """Deindent a list of lines maximally"""
+    return textwrap.dedent("\n".join(lines)).split("\n")
+
+def header(text, style='-'):
+    return text + '\n' + style*len(text) + '\n'
+
+
+class FunctionDoc(NumpyDocString):
+    def __init__(self, func, role='func', doc=None, config={}):
+        self._f = func
+        self._role = role # e.g. "func" or "meth"
+
+        if doc is None:
+            if func is None:
+                raise ValueError("No function or docstring given")
+            doc = inspect.getdoc(func) or ''
+        NumpyDocString.__init__(self, doc)
+
+        if not self['Signature'] and func is not None:
+            func, func_name = self.get_func()
+            try:
+                # try to read signature
+                argspec = inspect.getargspec(func)
+                argspec = inspect.formatargspec(*argspec)
+                argspec = argspec.replace('*','\*')
+                signature = '%s%s' % (func_name, argspec)
+            except TypeError as e:
+                signature = '%s()' % func_name
+            self['Signature'] = signature
+
+    def get_func(self):
+        func_name = getattr(self._f, '__name__', self.__class__.__name__)
+        if inspect.isclass(self._f):
+            func = getattr(self._f, '__call__', self._f.__init__)
+        else:
+            func = self._f
+        return func, func_name
+
+    def __str__(self):
+        out = ''
+
+        func, func_name = self.get_func()
+        signature = self['Signature'].replace('*', '\*')
+
+        roles = {'func': 'function',
+                 'meth': 'method'}
+
+        if self._role:
+            if self._role not in roles:
+                print("Warning: invalid role %s" % self._role)
+            out += '.. %s:: %s\n    \n\n' % (roles.get(self._role,''),
+                                             func_name)
+
+        out += super(FunctionDoc, self).__str__(func_role=self._role)
+        return out
+
+
+class ClassDoc(NumpyDocString):
+
+    def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc,
+                 config={}):
+        if not inspect.isclass(cls) and cls is not None:
+            raise ValueError("Expected a class or None, but got %r" % cls)
+        self._cls = cls
+
+        if modulename and not modulename.endswith('.'):
+            modulename += '.'
+        self._mod = modulename
+
+        if doc is None:
+            if cls is None:
+                raise ValueError("No class or documentation string given")
+            doc = pydoc.getdoc(cls)
+
+        NumpyDocString.__init__(self, doc)
+
+        if config.get('show_class_members', True):
+            def splitlines_x(s):
+                if not s:
+                    return []
+                else:
+                    return s.splitlines()
+
+            for field, items in [('Methods', self.methods),
+                                 ('Attributes', self.properties)]:
+                if not self[field]:
+                    doc_list = []
+                    for name in sorted(items):
+                         try:
+                            doc_item = pydoc.getdoc(getattr(self._cls, name))
+                            doc_list.append((name, '', splitlines_x(doc_item)))
+                         except AttributeError:
+                            pass # method doesn't exist
+                    self[field] = doc_list
+
+    @property
+    def methods(self):
+        if self._cls is None:
+            return []
+        return [name for name,func in inspect.getmembers(self._cls)
+                if ((not name.startswith('_') or
+                     '.. shownumpydoc' in pydoc.getdoc(func))
+                    and isinstance(func, collections.Callable))]
+
+    @property
+    def properties(self):
+        if self._cls is None:
+            return []
+        return [name for name,func in inspect.getmembers(self._cls)
+                if not name.startswith('_') and
+                (func is None or isinstance(func, property) or
+                 inspect.isgetsetdescriptor(func))]
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/docscrape_sphinx.py b/doc/source/sphinxext/numpydoc/numpydoc/docscrape_sphinx.py
new file mode 100644
index 0000000..cdc2a37
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/docscrape_sphinx.py
@@ -0,0 +1,274 @@
+from __future__ import division, absolute_import, print_function
+
+import sys, re, inspect, textwrap, pydoc
+import sphinx
+import collections
+from .docscrape import NumpyDocString, FunctionDoc, ClassDoc
+
+if sys.version_info[0] >= 3:
+    sixu = lambda s: s
+else:
+    sixu = lambda s: unicode(s, 'unicode_escape')
+
+
+class SphinxDocString(NumpyDocString):
+    def __init__(self, docstring, config={}):
+        NumpyDocString.__init__(self, docstring, config=config)
+        self.load_config(config)
+
+    def load_config(self, config):
+        self.use_plots = config.get('use_plots', False)
+        self.class_members_toctree = config.get('class_members_toctree', True)
+
+    # string conversion routines
+    def _str_header(self, name, symbol='`'):
+        return ['.. rubric:: ' + name, '']
+
+    def _str_field_list(self, name):
+        return [':' + name + ':']
+
+    def _str_indent(self, doc, indent=4):
+        out = []
+        for line in doc:
+            out += [' '*indent + line]
+        return out
+
+    def _str_signature(self):
+        return ['']
+        if self['Signature']:
+            return ['``%s``' % self['Signature']] + ['']
+        else:
+            return ['']
+
+    def _str_summary(self):
+        return self['Summary'] + ['']
+
+    def _str_extended_summary(self):
+        return self['Extended Summary'] + ['']
+
+    def _str_returns(self):
+        out = []
+        if self['Returns']:
+            out += self._str_field_list('Returns')
+            out += ['']
+            for param, param_type, desc in self['Returns']:
+                if param_type:
+                    out += self._str_indent(['**%s** : %s' % (param.strip(),
+                                                              param_type)])
+                else:
+                    out += self._str_indent([param.strip()])
+                if desc:
+                    out += ['']
+                    out += self._str_indent(desc, 8)
+                out += ['']
+        return out
+
+    def _str_param_list(self, name):
+        out = []
+        if self[name]:
+            out += self._str_field_list(name)
+            out += ['']
+            for param, param_type, desc in self[name]:
+                if param_type:
+                    out += self._str_indent(['**%s** : %s' % (param.strip(),
+                                                              param_type)])
+                else:
+                    out += self._str_indent(['**%s**' % param.strip()])
+                if desc:
+                    out += ['']
+                    out += self._str_indent(desc, 8)
+                out += ['']
+        return out
+
+    @property
+    def _obj(self):
+        if hasattr(self, '_cls'):
+            return self._cls
+        elif hasattr(self, '_f'):
+            return self._f
+        return None
+
+    def _str_member_list(self, name):
+        """
+        Generate a member listing, autosummary:: table where possible,
+        and a table where not.
+
+        """
+        out = []
+        if self[name]:
+            out += ['.. rubric:: %s' % name, '']
+            prefix = getattr(self, '_name', '')
+
+            if prefix:
+                prefix = '~%s.' % prefix
+
+            autosum = []
+            others = []
+            for param, param_type, desc in self[name]:
+                param = param.strip()
+
+                # Check if the referenced member can have a docstring or not
+                param_obj = getattr(self._obj, param, None)
+                if not (callable(param_obj)
+                        or isinstance(param_obj, property)
+                        or inspect.isgetsetdescriptor(param_obj)):
+                    param_obj = None
+
+                if param_obj and (pydoc.getdoc(param_obj) or not desc):
+                    # Referenced object has a docstring
+                    autosum += ["   %s%s" % (prefix, param)]
+                else:
+                    others.append((param, param_type, desc))
+
+            if autosum:
+                out += ['.. autosummary::']
+                if self.class_members_toctree:
+                    out += ['   :toctree:']
+                out += [''] + autosum
+
+            if others:
+                maxlen_0 = max(3, max([len(x[0]) for x in others]))
+                hdr = sixu("=")*maxlen_0 + sixu("  ") + sixu("=")*10
+                fmt = sixu('%%%ds  %%s  ') % (maxlen_0,)
+                out += ['', hdr]
+                for param, param_type, desc in others:
+                    desc = sixu(" ").join(x.strip() for x in desc).strip()
+                    if param_type:
+                        desc = "(%s) %s" % (param_type, desc)
+                    out += [fmt % (param.strip(), desc)]
+                out += [hdr]
+            out += ['']
+        return out
+
+    def _str_section(self, name):
+        out = []
+        if self[name]:
+            out += self._str_header(name)
+            out += ['']
+            content = textwrap.dedent("\n".join(self[name])).split("\n")
+            out += content
+            out += ['']
+        return out
+
+    def _str_see_also(self, func_role):
+        out = []
+        if self['See Also']:
+            see_also = super(SphinxDocString, self)._str_see_also(func_role)
+            out = ['.. seealso::', '']
+            out += self._str_indent(see_also[2:])
+        return out
+
+    def _str_warnings(self):
+        out = []
+        if self['Warnings']:
+            out = ['.. warning::', '']
+            out += self._str_indent(self['Warnings'])
+        return out
+
+    def _str_index(self):
+        idx = self['index']
+        out = []
+        if len(idx) == 0:
+            return out
+
+        out += ['.. index:: %s' % idx.get('default','')]
+        for section, references in idx.items():
+            if section == 'default':
+                continue
+            elif section == 'refguide':
+                out += ['   single: %s' % (', '.join(references))]
+            else:
+                out += ['   %s: %s' % (section, ','.join(references))]
+        return out
+
+    def _str_references(self):
+        out = []
+        if self['References']:
+            out += self._str_header('References')
+            if isinstance(self['References'], str):
+                self['References'] = [self['References']]
+            out.extend(self['References'])
+            out += ['']
+            # Latex collects all references to a separate bibliography,
+            # so we need to insert links to it
+            if sphinx.__version__ >= "0.6":
+                out += ['.. only:: latex','']
+            else:
+                out += ['.. latexonly::','']
+            items = []
+            for line in self['References']:
+                m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I)
+                if m:
+                    items.append(m.group(1))
+            out += ['   ' + ", ".join(["[%s]_" % item for item in items]), '']
+        return out
+
+    def _str_examples(self):
+        examples_str = "\n".join(self['Examples'])
+
+        if (self.use_plots and 'import matplotlib' in examples_str
+                and 'plot::' not in examples_str):
+            out = []
+            out += self._str_header('Examples')
+            out += ['.. plot::', '']
+            out += self._str_indent(self['Examples'])
+            out += ['']
+            return out
+        else:
+            return self._str_section('Examples')
+
+    def __str__(self, indent=0, func_role="obj"):
+        out = []
+        out += self._str_signature()
+        out += self._str_index() + ['']
+        out += self._str_summary()
+        out += self._str_extended_summary()
+        out += self._str_param_list('Parameters')
+        out += self._str_returns()
+        for param_list in ('Other Parameters', 'Raises', 'Warns'):
+            out += self._str_param_list(param_list)
+        out += self._str_warnings()
+        out += self._str_see_also(func_role)
+        out += self._str_section('Notes')
+        out += self._str_references()
+        out += self._str_examples()
+        for param_list in ('Attributes', 'Methods'):
+            out += self._str_member_list(param_list)
+        out = self._str_indent(out,indent)
+        return '\n'.join(out)
+
+class SphinxFunctionDoc(SphinxDocString, FunctionDoc):
+    def __init__(self, obj, doc=None, config={}):
+        self.load_config(config)
+        FunctionDoc.__init__(self, obj, doc=doc, config=config)
+
+class SphinxClassDoc(SphinxDocString, ClassDoc):
+    def __init__(self, obj, doc=None, func_doc=None, config={}):
+        self.load_config(config)
+        ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config)
+
+class SphinxObjDoc(SphinxDocString):
+    def __init__(self, obj, doc=None, config={}):
+        self._f = obj
+        self.load_config(config)
+        SphinxDocString.__init__(self, doc, config=config)
+
+def get_doc_object(obj, what=None, doc=None, config={}):
+    if what is None:
+        if inspect.isclass(obj):
+            what = 'class'
+        elif inspect.ismodule(obj):
+            what = 'module'
+        elif isinstance(obj, collections.Callable):
+            what = 'function'
+        else:
+            what = 'object'
+    if what == 'class':
+        return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc,
+                              config=config)
+    elif what in ('function', 'method'):
+        return SphinxFunctionDoc(obj, doc=doc, config=config)
+    else:
+        if doc is None:
+            doc = pydoc.getdoc(obj)
+        return SphinxObjDoc(obj, doc, config=config)
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/linkcode.py b/doc/source/sphinxext/numpydoc/numpydoc/linkcode.py
new file mode 100644
index 0000000..1ad3ab8
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/linkcode.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+"""
+    linkcode
+    ~~~~~~~~
+
+    Add external links to module code in Python object descriptions.
+
+    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import warnings
+import collections
+
+warnings.warn("This extension has been accepted to Sphinx upstream. "
+              "Use the version from there (Sphinx >= 1.2) "
+              "https://bitbucket.org/birkenfeld/sphinx/pull-request/47/sphinxextlinkcode",
+              FutureWarning, stacklevel=1)
+
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.locale import _
+from sphinx.errors import SphinxError
+
+class LinkcodeError(SphinxError):
+    category = "linkcode error"
+
+def doctree_read(app, doctree):
+    env = app.builder.env
+
+    resolve_target = getattr(env.config, 'linkcode_resolve', None)
+    if not isinstance(env.config.linkcode_resolve, collections.Callable):
+        raise LinkcodeError(
+            "Function `linkcode_resolve` is not given in conf.py")
+
+    domain_keys = dict(
+        py=['module', 'fullname'],
+        c=['names'],
+        cpp=['names'],
+        js=['object', 'fullname'],
+    )
+
+    for objnode in doctree.traverse(addnodes.desc):
+        domain = objnode.get('domain')
+        uris = set()
+        for signode in objnode:
+            if not isinstance(signode, addnodes.desc_signature):
+                continue
+
+            # Convert signode to a specified format
+            info = {}
+            for key in domain_keys.get(domain, []):
+                value = signode.get(key)
+                if not value:
+                    value = ''
+                info[key] = value
+            if not info:
+                continue
+
+            # Call user code to resolve the link
+            uri = resolve_target(domain, info)
+            if not uri:
+                # no source
+                continue
+
+            if uri in uris or not uri:
+                # only one link per name, please
+                continue
+            uris.add(uri)
+
+            onlynode = addnodes.only(expr='html')
+            onlynode += nodes.reference('', '', internal=False, refuri=uri)
+            onlynode[0] += nodes.inline('', _('[source]'),
+                                        classes=['viewcode-link'])
+            signode += onlynode
+
+def setup(app):
+    app.connect('doctree-read', doctree_read)
+    app.add_config_value('linkcode_resolve', None, '')
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/numpydoc.py b/doc/source/sphinxext/numpydoc/numpydoc/numpydoc.py
new file mode 100644
index 0000000..2bc2d1e
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/numpydoc.py
@@ -0,0 +1,187 @@
+"""
+========
+numpydoc
+========
+
+Sphinx extension that handles docstrings in the Numpy standard format. [1]
+
+It will:
+
+- Convert Parameters etc. sections to field lists.
+- Convert See Also section to a See also entry.
+- Renumber references.
+- Extract the signature from the docstring, if it can't be determined otherwise.
+
+.. [1] https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import os, sys, re, pydoc
+import sphinx
+import inspect
+import collections
+
+if sphinx.__version__ < '1.0.1':
+    raise RuntimeError("Sphinx 1.0.1 or newer is required")
+
+from .docscrape_sphinx import get_doc_object, SphinxDocString
+from sphinx.util.compat import Directive
+
+if sys.version_info[0] >= 3:
+    sixu = lambda s: s
+else:
+    sixu = lambda s: unicode(s, 'unicode_escape')
+
+
+def mangle_docstrings(app, what, name, obj, options, lines,
+                      reference_offset=[0]):
+
+    cfg = dict(use_plots=app.config.numpydoc_use_plots,
+               show_class_members=app.config.numpydoc_show_class_members,
+               class_members_toctree=app.config.numpydoc_class_members_toctree,
+              )
+
+    if what == 'module':
+        # Strip top title
+        title_re = re.compile(sixu('^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*'),
+                              re.I|re.S)
+        lines[:] = title_re.sub(sixu(''), sixu("\n").join(lines)).split(sixu("\n"))
+    else:
+        doc = get_doc_object(obj, what, sixu("\n").join(lines), config=cfg)
+        if sys.version_info[0] >= 3:
+            doc = str(doc)
+        else:
+            doc = unicode(doc)
+        lines[:] = doc.split(sixu("\n"))
+
+    if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \
+           obj.__name__:
+        if hasattr(obj, '__module__'):
+            v = dict(full_name=sixu("%s.%s") % (obj.__module__, obj.__name__))
+        else:
+            v = dict(full_name=obj.__name__)
+        lines += [sixu(''), sixu('.. htmlonly::'), sixu('')]
+        lines += [sixu('    %s') % x for x in
+                  (app.config.numpydoc_edit_link % v).split("\n")]
+
+    # replace reference numbers so that there are no duplicates
+    references = []
+    for line in lines:
+        line = line.strip()
+        m = re.match(sixu('^.. \\[([a-z0-9_.-])\\]'), line, re.I)
+        if m:
+            references.append(m.group(1))
+
+    # start renaming from the longest string, to avoid overwriting parts
+    references.sort(key=lambda x: -len(x))
+    if references:
+        for i, line in enumerate(lines):
+            for r in references:
+                if re.match(sixu('^\\d+$'), r):
+                    new_r = sixu("R%d") % (reference_offset[0] + int(r))
+                else:
+                    new_r = sixu("%s%d") % (r, reference_offset[0])
+                lines[i] = lines[i].replace(sixu('[%s]_') % r,
+                                            sixu('[%s]_') % new_r)
+                lines[i] = lines[i].replace(sixu('.. [%s]') % r,
+                                            sixu('.. [%s]') % new_r)
+
+    reference_offset[0] += len(references)
+
+def mangle_signature(app, what, name, obj, options, sig, retann):
+    # Do not try to inspect classes that don't define `__init__`
+    if (inspect.isclass(obj) and
+        (not hasattr(obj, '__init__') or
+        'initializes x; see ' in pydoc.getdoc(obj.__init__))):
+        return '', ''
+
+    if not (isinstance(obj, collections.Callable) or hasattr(obj, '__argspec_is_invalid_')): return
+    if not hasattr(obj, '__doc__'): return
+
+    doc = SphinxDocString(pydoc.getdoc(obj))
+    if doc['Signature']:
+        sig = re.sub(sixu("^[^(]*"), sixu(""), doc['Signature'])
+        return sig, sixu('')
+
+def setup(app, get_doc_object_=get_doc_object):
+    if not hasattr(app, 'add_config_value'):
+        return # probably called by nose, better bail out
+
+    global get_doc_object
+    get_doc_object = get_doc_object_
+
+    app.connect('autodoc-process-docstring', mangle_docstrings)
+    app.connect('autodoc-process-signature', mangle_signature)
+    app.add_config_value('numpydoc_edit_link', None, False)
+    app.add_config_value('numpydoc_use_plots', None, False)
+    app.add_config_value('numpydoc_show_class_members', True, True)
+    app.add_config_value('numpydoc_class_members_toctree', True, True)
+
+    # Extra mangling domains
+    app.add_domain(NumpyPythonDomain)
+    app.add_domain(NumpyCDomain)
+
+#------------------------------------------------------------------------------
+# Docstring-mangling domains
+#------------------------------------------------------------------------------
+
+from docutils.statemachine import ViewList
+from sphinx.domains.c import CDomain
+from sphinx.domains.python import PythonDomain
+
+class ManglingDomainBase(object):
+    directive_mangling_map = {}
+
+    def __init__(self, *a, **kw):
+        super(ManglingDomainBase, self).__init__(*a, **kw)
+        self.wrap_mangling_directives()
+
+    def wrap_mangling_directives(self):
+        for name, objtype in list(self.directive_mangling_map.items()):
+            self.directives[name] = wrap_mangling_directive(
+                self.directives[name], objtype)
+
+class NumpyPythonDomain(ManglingDomainBase, PythonDomain):
+    name = 'np'
+    directive_mangling_map = {
+        'function': 'function',
+        'class': 'class',
+        'exception': 'class',
+        'method': 'function',
+        'classmethod': 'function',
+        'staticmethod': 'function',
+        'attribute': 'attribute',
+    }
+    indices = []
+
+class NumpyCDomain(ManglingDomainBase, CDomain):
+    name = 'np-c'
+    directive_mangling_map = {
+        'function': 'function',
+        'member': 'attribute',
+        'macro': 'function',
+        'type': 'class',
+        'var': 'object',
+    }
+
+def wrap_mangling_directive(base_directive, objtype):
+    class directive(base_directive):
+        def run(self):
+            env = self.state.document.settings.env
+
+            name = None
+            if self.arguments:
+                m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0])
+                name = m.group(2).strip()
+
+            if not name:
+                name = self.arguments[0]
+
+            lines = list(self.content)
+            mangle_docstrings(env.app, objtype, name, None, None, lines)
+            self.content = ViewList(lines, self.content.parent)
+
+            return base_directive.run(self)
+
+    return directive
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/phantom_import.py b/doc/source/sphinxext/numpydoc/numpydoc/phantom_import.py
new file mode 100644
index 0000000..9a60b4a
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/phantom_import.py
@@ -0,0 +1,167 @@
+"""
+==============
+phantom_import
+==============
+
+Sphinx extension to make directives from ``sphinx.ext.autodoc`` and similar
+extensions to use docstrings loaded from an XML file.
+
+This extension loads an XML file in the Pydocweb format [1] and
+creates a dummy module that contains the specified docstrings. This
+can be used to get the current docstrings from a Pydocweb instance
+without needing to rebuild the documented module.
+
+.. [1] http://code.google.com/p/pydocweb
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import imp, sys, compiler, types, os, inspect, re
+
+def setup(app):
+    app.connect('builder-inited', initialize)
+    app.add_config_value('phantom_import_file', None, True)
+
+def initialize(app):
+    fn = app.config.phantom_import_file
+    if (fn and os.path.isfile(fn)):
+        print("[numpydoc] Phantom importing modules from", fn, "...")
+        import_phantom_module(fn)
+
+#------------------------------------------------------------------------------
+# Creating 'phantom' modules from an XML description
+#------------------------------------------------------------------------------
+def import_phantom_module(xml_file):
+    """
+    Insert a fake Python module to sys.modules, based on a XML file.
+
+    The XML file is expected to conform to Pydocweb DTD. The fake
+    module will contain dummy objects, which guarantee the following:
+
+    - Docstrings are correct.
+    - Class inheritance relationships are correct (if present in XML).
+    - Function argspec is *NOT* correct (even if present in XML).
+      Instead, the function signature is prepended to the function docstring.
+    - Class attributes are *NOT* correct; instead, they are dummy objects.
+
+    Parameters
+    ----------
+    xml_file : str
+        Name of an XML file to read
+    
+    """
+    import lxml.etree as etree
+
+    object_cache = {}
+
+    tree = etree.parse(xml_file)
+    root = tree.getroot()
+
+    # Sort items so that
+    # - Base classes come before classes inherited from them
+    # - Modules come before their contents
+    all_nodes = dict([(n.attrib['id'], n) for n in root])
+    
+    def _get_bases(node, recurse=False):
+        bases = [x.attrib['ref'] for x in node.findall('base')]
+        if recurse:
+            j = 0
+            while True:
+                try:
+                    b = bases[j]
+                except IndexError: break
+                if b in all_nodes:
+                    bases.extend(_get_bases(all_nodes[b]))
+                j += 1
+        return bases
+
+    type_index = ['module', 'class', 'callable', 'object']
+    
+    def base_cmp(a, b):
+        x = cmp(type_index.index(a.tag), type_index.index(b.tag))
+        if x != 0: return x
+
+        if a.tag == 'class' and b.tag == 'class':
+            a_bases = _get_bases(a, recurse=True)
+            b_bases = _get_bases(b, recurse=True)
+            x = cmp(len(a_bases), len(b_bases))
+            if x != 0: return x
+            if a.attrib['id'] in b_bases: return -1
+            if b.attrib['id'] in a_bases: return 1
+        
+        return cmp(a.attrib['id'].count('.'), b.attrib['id'].count('.'))
+
+    nodes = root.getchildren()
+    nodes.sort(base_cmp)
+
+    # Create phantom items
+    for node in nodes:
+        name = node.attrib['id']
+        doc = (node.text or '').decode('string-escape') + "\n"
+        if doc == "\n": doc = ""
+
+        # create parent, if missing
+        parent = name
+        while True:
+            parent = '.'.join(parent.split('.')[:-1])
+            if not parent: break
+            if parent in object_cache: break
+            obj = imp.new_module(parent)
+            object_cache[parent] = obj
+            sys.modules[parent] = obj
+
+        # create object
+        if node.tag == 'module':
+            obj = imp.new_module(name)
+            obj.__doc__ = doc
+            sys.modules[name] = obj
+        elif node.tag == 'class':
+            bases = [object_cache[b] for b in _get_bases(node)
+                     if b in object_cache]
+            bases.append(object)
+            init = lambda self: None
+            init.__doc__ = doc
+            obj = type(name, tuple(bases), {'__doc__': doc, '__init__': init})
+            obj.__name__ = name.split('.')[-1]
+        elif node.tag == 'callable':
+            funcname = node.attrib['id'].split('.')[-1]
+            argspec = node.attrib.get('argspec')
+            if argspec:
+                argspec = re.sub('^[^(]*', '', argspec)
+                doc = "%s%s\n\n%s" % (funcname, argspec, doc)
+            obj = lambda: 0
+            obj.__argspec_is_invalid_ = True
+            if sys.version_info[0] >= 3:
+                obj.__name__ = funcname
+            else:
+                obj.func_name = funcname
+            obj.__name__ = name
+            obj.__doc__ = doc
+            if inspect.isclass(object_cache[parent]):
+                obj.__objclass__ = object_cache[parent]
+        else:
+            class Dummy(object): pass
+            obj = Dummy()
+            obj.__name__ = name
+            obj.__doc__ = doc
+            if inspect.isclass(object_cache[parent]):
+                obj.__get__ = lambda: None
+        object_cache[name] = obj
+
+        if parent:
+            if inspect.ismodule(object_cache[parent]):
+                obj.__module__ = parent
+                setattr(object_cache[parent], name.split('.')[-1], obj)
+
+    # Populate items
+    for node in root:
+        obj = object_cache.get(node.attrib['id'])
+        if obj is None: continue
+        for ref in node.findall('ref'):
+            if node.tag == 'class':
+                if ref.attrib['ref'].startswith(node.attrib['id'] + '.'):
+                    setattr(obj, ref.attrib['name'],
+                            object_cache.get(ref.attrib['ref']))
+            else:
+                setattr(obj, ref.attrib['name'],
+                        object_cache.get(ref.attrib['ref']))
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/plot_directive.py b/doc/source/sphinxext/numpydoc/numpydoc/plot_directive.py
new file mode 100644
index 0000000..2014f85
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/plot_directive.py
@@ -0,0 +1,642 @@
+"""
+A special directive for generating a matplotlib plot.
+
+.. warning::
+
+   This is a hacked version of plot_directive.py from Matplotlib.
+   It's very much subject to change!
+
+
+Usage
+-----
+
+Can be used like this::
+
+    .. plot:: examples/example.py
+
+    .. plot::
+
+       import matplotlib.pyplot as plt
+       plt.plot([1,2,3], [4,5,6])
+
+    .. plot::
+
+       A plotting example:
+
+       >>> import matplotlib.pyplot as plt
+       >>> plt.plot([1,2,3], [4,5,6])
+
+The content is interpreted as doctest formatted if it has a line starting
+with ``>>>``.
+
+The ``plot`` directive supports the options
+
+    format : {'python', 'doctest'}
+        Specify the format of the input
+
+    include-source : bool
+        Whether to display the source code. Default can be changed in conf.py
+
+and the ``image`` directive options ``alt``, ``height``, ``width``,
+``scale``, ``align``, ``class``.
+
+Configuration options
+---------------------
+
+The plot directive has the following configuration options:
+
+    plot_include_source
+        Default value for the include-source option
+
+    plot_pre_code
+        Code that should be executed before each plot.
+
+    plot_basedir
+        Base directory, to which plot:: file names are relative to.
+        (If None or empty, file names are relative to the directoly where
+        the file containing the directive is.)
+
+    plot_formats
+        File formats to generate. List of tuples or strings::
+
+            [(suffix, dpi), suffix, ...]
+
+        that determine the file format and the DPI. For entries whose
+        DPI was omitted, sensible defaults are chosen.
+
+    plot_html_show_formats
+        Whether to show links to the files in HTML.
+
+TODO
+----
+
+* Refactor Latex output; now it's plain images, but it would be nice
+  to make them appear side-by-side, or in floats.
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import sys, os, glob, shutil, imp, warnings, re, textwrap, traceback
+import sphinx
+
+if sys.version_info[0] >= 3:
+    from io import StringIO
+else:
+    from io import StringIO
+
+import warnings
+warnings.warn("A plot_directive module is also available under "
+              "matplotlib.sphinxext; expect this numpydoc.plot_directive "
+              "module to be deprecated after relevant features have been "
+              "integrated there.",
+              FutureWarning, stacklevel=2)
+
+
+#------------------------------------------------------------------------------
+# Registration hook
+#------------------------------------------------------------------------------
+
+def setup(app):
+    setup.app = app
+    setup.config = app.config
+    setup.confdir = app.confdir
+
+    app.add_config_value('plot_pre_code', '', True)
+    app.add_config_value('plot_include_source', False, True)
+    app.add_config_value('plot_formats', ['png', 'hires.png', 'pdf'], True)
+    app.add_config_value('plot_basedir', None, True)
+    app.add_config_value('plot_html_show_formats', True, True)
+
+    app.add_directive('plot', plot_directive, True, (0, 1, False),
+                      **plot_directive_options)
+
+#------------------------------------------------------------------------------
+# plot:: directive
+#------------------------------------------------------------------------------
+from docutils.parsers.rst import directives
+from docutils import nodes
+
+def plot_directive(name, arguments, options, content, lineno,
+                   content_offset, block_text, state, state_machine):
+    return run(arguments, content, options, state_machine, state, lineno)
+plot_directive.__doc__ = __doc__
+
+def _option_boolean(arg):
+    if not arg or not arg.strip():
+        # no argument given, assume used as a flag
+        return True
+    elif arg.strip().lower() in ('no', '0', 'false'):
+        return False
+    elif arg.strip().lower() in ('yes', '1', 'true'):
+        return True
+    else:
+        raise ValueError('"%s" unknown boolean' % arg)
+
+def _option_format(arg):
+    return directives.choice(arg, ('python', 'lisp'))
+
+def _option_align(arg):
+    return directives.choice(arg, ("top", "middle", "bottom", "left", "center",
+                                   "right"))
+
+plot_directive_options = {'alt': directives.unchanged,
+                          'height': directives.length_or_unitless,
+                          'width': directives.length_or_percentage_or_unitless,
+                          'scale': directives.nonnegative_int,
+                          'align': _option_align,
+                          'class': directives.class_option,
+                          'include-source': _option_boolean,
+                          'format': _option_format,
+                          }
+
+#------------------------------------------------------------------------------
+# Generating output
+#------------------------------------------------------------------------------
+
+from docutils import nodes, utils
+
+try:
+    # Sphinx depends on either Jinja or Jinja2
+    import jinja2
+    def format_template(template, **kw):
+        return jinja2.Template(template).render(**kw)
+except ImportError:
+    import jinja
+    def format_template(template, **kw):
+        return jinja.from_string(template, **kw)
+
+TEMPLATE = """
+{{ source_code }}
+
+{{ only_html }}
+
+   {% if source_link or (html_show_formats and not multi_image) %}
+   (
+   {%- if source_link -%}
+   `Source code <{{ source_link }}>`__
+   {%- endif -%}
+   {%- if html_show_formats and not multi_image -%}
+     {%- for img in images -%}
+       {%- for fmt in img.formats -%}
+         {%- if source_link or not loop.first -%}, {% endif -%}
+         `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__
+       {%- endfor -%}
+     {%- endfor -%}
+   {%- endif -%}
+   )
+   {% endif %}
+
+   {% for img in images %}
+   .. figure:: {{ build_dir }}/{{ img.basename }}.png
+      {%- for option in options %}
+      {{ option }}
+      {% endfor %}
+
+      {% if html_show_formats and multi_image -%}
+        (
+        {%- for fmt in img.formats -%}
+        {%- if not loop.first -%}, {% endif -%}
+        `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__
+        {%- endfor -%}
+        )
+      {%- endif -%}
+   {% endfor %}
+
+{{ only_latex }}
+
+   {% for img in images %}
+   .. image:: {{ build_dir }}/{{ img.basename }}.pdf
+   {% endfor %}
+
+"""
+
+class ImageFile(object):
+    def __init__(self, basename, dirname):
+        self.basename = basename
+        self.dirname = dirname
+        self.formats = []
+
+    def filename(self, format):
+        return os.path.join(self.dirname, "%s.%s" % (self.basename, format))
+
+    def filenames(self):
+        return [self.filename(fmt) for fmt in self.formats]
+
+def run(arguments, content, options, state_machine, state, lineno):
+    if arguments and content:
+        raise RuntimeError("plot:: directive can't have both args and content")
+
+    document = state_machine.document
+    config = document.settings.env.config
+
+    options.setdefault('include-source', config.plot_include_source)
+
+    # determine input
+    rst_file = document.attributes['source']
+    rst_dir = os.path.dirname(rst_file)
+
+    if arguments:
+        if not config.plot_basedir:
+            source_file_name = os.path.join(rst_dir,
+                                            directives.uri(arguments[0]))
+        else:
+            source_file_name = os.path.join(setup.confdir, config.plot_basedir,
+                                            directives.uri(arguments[0]))
+        code = open(source_file_name, 'r').read()
+        output_base = os.path.basename(source_file_name)
+    else:
+        source_file_name = rst_file
+        code = textwrap.dedent("\n".join(map(str, content)))
+        counter = document.attributes.get('_plot_counter', 0) + 1
+        document.attributes['_plot_counter'] = counter
+        base, ext = os.path.splitext(os.path.basename(source_file_name))
+        output_base = '%s-%d.py' % (base, counter)
+
+    base, source_ext = os.path.splitext(output_base)
+    if source_ext in ('.py', '.rst', '.txt'):
+        output_base = base
+    else:
+        source_ext = ''
+
+    # ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames
+    output_base = output_base.replace('.', '-')
+
+    # is it in doctest format?
+    is_doctest = contains_doctest(code)
+    if 'format' in options:
+        if options['format'] == 'python':
+            is_doctest = False
+        else:
+            is_doctest = True
+
+    # determine output directory name fragment
+    source_rel_name = relpath(source_file_name, setup.confdir)
+    source_rel_dir = os.path.dirname(source_rel_name)
+    while source_rel_dir.startswith(os.path.sep):
+        source_rel_dir = source_rel_dir[1:]
+
+    # build_dir: where to place output files (temporarily)
+    build_dir = os.path.join(os.path.dirname(setup.app.doctreedir),
+                             'plot_directive',
+                             source_rel_dir)
+    if not os.path.exists(build_dir):
+        os.makedirs(build_dir)
+
+    # output_dir: final location in the builder's directory
+    dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir,
+                                            source_rel_dir))
+
+    # how to link to files from the RST file
+    dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir),
+                                 source_rel_dir).replace(os.path.sep, '/')
+    build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/')
+    source_link = dest_dir_link + '/' + output_base + source_ext
+
+    # make figures
+    try:
+        results = makefig(code, source_file_name, build_dir, output_base,
+                          config)
+        errors = []
+    except PlotError as err:
+        reporter = state.memo.reporter
+        sm = reporter.system_message(
+            2, "Exception occurred in plotting %s: %s" % (output_base, err),
+            line=lineno)
+        results = [(code, [])]
+        errors = [sm]
+
+    # generate output restructuredtext
+    total_lines = []
+    for j, (code_piece, images) in enumerate(results):
+        if options['include-source']:
+            if is_doctest:
+                lines = ['']
+                lines += [row.rstrip() for row in code_piece.split('\n')]
+            else:
+                lines = ['.. code-block:: python', '']
+                lines += ['    %s' % row.rstrip()
+                          for row in code_piece.split('\n')]
+            source_code = "\n".join(lines)
+        else:
+            source_code = ""
+
+        opts = [':%s: %s' % (key, val) for key, val in list(options.items())
+                if key in ('alt', 'height', 'width', 'scale', 'align', 'class')]
+
+        only_html = ".. only:: html"
+        only_latex = ".. only:: latex"
+
+        if j == 0:
+            src_link = source_link
+        else:
+            src_link = None
+
+        result = format_template(
+            TEMPLATE,
+            dest_dir=dest_dir_link,
+            build_dir=build_dir_link,
+            source_link=src_link,
+            multi_image=len(images) > 1,
+            only_html=only_html,
+            only_latex=only_latex,
+            options=opts,
+            images=images,
+            source_code=source_code,
+            html_show_formats=config.plot_html_show_formats)
+
+        total_lines.extend(result.split("\n"))
+        total_lines.extend("\n")
+
+    if total_lines:
+        state_machine.insert_input(total_lines, source=source_file_name)
+
+    # copy image files to builder's output directory
+    if not os.path.exists(dest_dir):
+        os.makedirs(dest_dir)
+
+    for code_piece, images in results:
+        for img in images:
+            for fn in img.filenames():
+                shutil.copyfile(fn, os.path.join(dest_dir,
+                                                 os.path.basename(fn)))
+
+    # copy script (if necessary)
+    if source_file_name == rst_file:
+        target_name = os.path.join(dest_dir, output_base + source_ext)
+        f = open(target_name, 'w')
+        f.write(unescape_doctest(code))
+        f.close()
+
+    return errors
+
+
+#------------------------------------------------------------------------------
+# Run code and capture figures
+#------------------------------------------------------------------------------
+
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+import matplotlib.image as image
+from matplotlib import _pylab_helpers
+
+import exceptions
+
+def contains_doctest(text):
+    try:
+        # check if it's valid Python as-is
+        compile(text, '<string>', 'exec')
+        return False
+    except SyntaxError:
+        pass
+    r = re.compile(r'^\s*>>>', re.M)
+    m = r.search(text)
+    return bool(m)
+
+def unescape_doctest(text):
+    """
+    Extract code from a piece of text, which contains either Python code
+    or doctests.
+
+    """
+    if not contains_doctest(text):
+        return text
+
+    code = ""
+    for line in text.split("\n"):
+        m = re.match(r'^\s*(>>>|\.\.\.) (.*)$', line)
+        if m:
+            code += m.group(2) + "\n"
+        elif line.strip():
+            code += "# " + line.strip() + "\n"
+        else:
+            code += "\n"
+    return code
+
+def split_code_at_show(text):
+    """
+    Split code at plt.show()
+
+    """
+
+    parts = []
+    is_doctest = contains_doctest(text)
+
+    part = []
+    for line in text.split("\n"):
+        if (not is_doctest and line.strip() == 'plt.show()') or \
+               (is_doctest and line.strip() == '>>> plt.show()'):
+            part.append(line)
+            parts.append("\n".join(part))
+            part = []
+        else:
+            part.append(line)
+    if "\n".join(part).strip():
+        parts.append("\n".join(part))
+    return parts
+
+class PlotError(RuntimeError):
+    pass
+
+def run_code(code, code_path, ns=None):
+    # Change the working directory to the directory of the example, so
+    # it can get at its data files, if any.
+    pwd = os.getcwd()
+    old_sys_path = list(sys.path)
+    if code_path is not None:
+        dirname = os.path.abspath(os.path.dirname(code_path))
+        os.chdir(dirname)
+        sys.path.insert(0, dirname)
+
+    # Redirect stdout
+    stdout = sys.stdout
+    sys.stdout = StringIO()
+
+    # Reset sys.argv
+    old_sys_argv = sys.argv
+    sys.argv = [code_path]
+    
+    try:
+        try:
+            code = unescape_doctest(code)
+            if ns is None:
+                ns = {}
+            if not ns:
+                exec(setup.config.plot_pre_code, ns)
+            exec(code, ns)
+        except (Exception, SystemExit) as err:
+            raise PlotError(traceback.format_exc())
+    finally:
+        os.chdir(pwd)
+        sys.argv = old_sys_argv
+        sys.path[:] = old_sys_path
+        sys.stdout = stdout
+    return ns
+
+
+#------------------------------------------------------------------------------
+# Generating figures
+#------------------------------------------------------------------------------
+
+def out_of_date(original, derived):
+    """
+    Returns True if derivative is out-of-date wrt original,
+    both of which are full file paths.
+    """
+    return (not os.path.exists(derived)
+            or os.stat(derived).st_mtime < os.stat(original).st_mtime)
+
+
+def makefig(code, code_path, output_dir, output_base, config):
+    """
+    Run a pyplot script *code* and save the images under *output_dir*
+    with file names derived from *output_base*
+
+    """
+
+    # -- Parse format list
+    default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 50}
+    formats = []
+    for fmt in config.plot_formats:
+        if isinstance(fmt, str):
+            formats.append((fmt, default_dpi.get(fmt, 80)))
+        elif type(fmt) in (tuple, list) and len(fmt)==2:
+            formats.append((str(fmt[0]), int(fmt[1])))
+        else:
+            raise PlotError('invalid image format "%r" in plot_formats' % fmt)
+
+    # -- Try to determine if all images already exist
+
+    code_pieces = split_code_at_show(code)
+
+    # Look for single-figure output files first
+    all_exists = True
+    img = ImageFile(output_base, output_dir)
+    for format, dpi in formats:
+        if out_of_date(code_path, img.filename(format)):
+            all_exists = False
+            break
+        img.formats.append(format)
+
+    if all_exists:
+        return [(code, [img])]
+
+    # Then look for multi-figure output files
+    results = []
+    all_exists = True
+    for i, code_piece in enumerate(code_pieces):
+        images = []
+        for j in range(1000):
+            img = ImageFile('%s_%02d_%02d' % (output_base, i, j), output_dir)
+            for format, dpi in formats:
+                if out_of_date(code_path, img.filename(format)):
+                    all_exists = False
+                    break
+                img.formats.append(format)
+
+            # assume that if we have one, we have them all
+            if not all_exists:
+                all_exists = (j > 0)
+                break
+            images.append(img)
+        if not all_exists:
+            break
+        results.append((code_piece, images))
+
+    if all_exists:
+        return results
+
+    # -- We didn't find the files, so build them
+
+    results = []
+    ns = {}
+
+    for i, code_piece in enumerate(code_pieces):
+        # Clear between runs
+        plt.close('all')
+
+        # Run code
+        run_code(code_piece, code_path, ns)
+
+        # Collect images
+        images = []
+        fig_managers = _pylab_helpers.Gcf.get_all_fig_managers()
+        for j, figman in enumerate(fig_managers):
+            if len(fig_managers) == 1 and len(code_pieces) == 1:
+                img = ImageFile(output_base, output_dir)
+            else:
+                img = ImageFile("%s_%02d_%02d" % (output_base, i, j),
+                                output_dir)
+            images.append(img)
+            for format, dpi in formats:
+                try:
+                    figman.canvas.figure.savefig(img.filename(format), dpi=dpi)
+                except exceptions.BaseException as err:
+                    raise PlotError(traceback.format_exc())
+                img.formats.append(format)
+
+        # Results
+        results.append((code_piece, images))
+
+    return results
+
+
+#------------------------------------------------------------------------------
+# Relative pathnames
+#------------------------------------------------------------------------------
+
+try:
+    from os.path import relpath
+except ImportError:
+    # Copied from Python 2.7
+    if 'posix' in sys.builtin_module_names:
+        def relpath(path, start=os.path.curdir):
+            """Return a relative version of a path"""
+            from os.path import sep, curdir, join, abspath, commonprefix, \
+                 pardir
+
+            if not path:
+                raise ValueError("no path specified")
+
+            start_list = abspath(start).split(sep)
+            path_list = abspath(path).split(sep)
+
+            # Work out how much of the filepath is shared by start and path.
+            i = len(commonprefix([start_list, path_list]))
+
+            rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+            if not rel_list:
+                return curdir
+            return join(*rel_list)
+    elif 'nt' in sys.builtin_module_names:
+        def relpath(path, start=os.path.curdir):
+            """Return a relative version of a path"""
+            from os.path import sep, curdir, join, abspath, commonprefix, \
+                 pardir, splitunc
+
+            if not path:
+                raise ValueError("no path specified")
+            start_list = abspath(start).split(sep)
+            path_list = abspath(path).split(sep)
+            if start_list[0].lower() != path_list[0].lower():
+                unc_path, rest = splitunc(path)
+                unc_start, rest = splitunc(start)
+                if bool(unc_path) ^ bool(unc_start):
+                    raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
+                                                                        % (path, start))
+                else:
+                    raise ValueError("path is on drive %s, start on drive %s"
+                                                        % (path_list[0], start_list[0]))
+            # Work out how much of the filepath is shared by start and path.
+            for i in range(min(len(start_list), len(path_list))):
+                if start_list[i].lower() != path_list[i].lower():
+                    break
+            else:
+                i += 1
+
+            rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+            if not rel_list:
+                return curdir
+            return join(*rel_list)
+    else:
+        raise RuntimeError("Unsupported platform (no relpath available!)")
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/tests/test_docscrape.py b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_docscrape.py
new file mode 100644
index 0000000..b682504
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_docscrape.py
@@ -0,0 +1,767 @@
+# -*- encoding:utf-8 -*-
+from __future__ import division, absolute_import, print_function
+
+import sys, textwrap
+
+from numpydoc.docscrape import NumpyDocString, FunctionDoc, ClassDoc
+from numpydoc.docscrape_sphinx import SphinxDocString, SphinxClassDoc
+from nose.tools import *
+
+if sys.version_info[0] >= 3:
+    sixu = lambda s: s
+else:
+    sixu = lambda s: unicode(s, 'unicode_escape')
+
+
+doc_txt = '''\
+  numpy.multivariate_normal(mean, cov, shape=None, spam=None)
+
+  Draw values from a multivariate normal distribution with specified
+  mean and covariance.
+
+  The multivariate normal or Gaussian distribution is a generalisation
+  of the one-dimensional normal distribution to higher dimensions.
+
+  Parameters
+  ----------
+  mean : (N,) ndarray
+      Mean of the N-dimensional distribution.
+
+      .. math::
+
+         (1+2+3)/3
+
+  cov : (N, N) ndarray
+      Covariance matrix of the distribution.
+  shape : tuple of ints
+      Given a shape of, for example, (m,n,k), m*n*k samples are
+      generated, and packed in an m-by-n-by-k arrangement.  Because
+      each sample is N-dimensional, the output shape is (m,n,k,N).
+
+  Returns
+  -------
+  out : ndarray
+      The drawn samples, arranged according to `shape`.  If the
+      shape given is (m,n,...), then the shape of `out` is is
+      (m,n,...,N).
+
+      In other words, each entry ``out[i,j,...,:]`` is an N-dimensional
+      value drawn from the distribution.
+  list of str
+      This is not a real return value.  It exists to test
+      anonymous return values.
+
+  Other Parameters
+  ----------------
+  spam : parrot
+      A parrot off its mortal coil.
+
+  Raises
+  ------
+  RuntimeError
+      Some error
+
+  Warns
+  -----
+  RuntimeWarning
+      Some warning
+
+  Warnings
+  --------
+  Certain warnings apply.
+
+  Notes
+  -----
+  Instead of specifying the full covariance matrix, popular
+  approximations include:
+
+    - Spherical covariance (`cov` is a multiple of the identity matrix)
+    - Diagonal covariance (`cov` has non-negative elements only on the diagonal)
+
+  This geometrical property can be seen in two dimensions by plotting
+  generated data-points:
+
+  >>> mean = [0,0]
+  >>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis
+
+  >>> x,y = multivariate_normal(mean,cov,5000).T
+  >>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show()
+
+  Note that the covariance matrix must be symmetric and non-negative
+  definite.
+
+  References
+  ----------
+  .. [1] A. Papoulis, "Probability, Random Variables, and Stochastic
+         Processes," 3rd ed., McGraw-Hill Companies, 1991
+  .. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification,"
+         2nd ed., Wiley, 2001.
+
+  See Also
+  --------
+  some, other, funcs
+  otherfunc : relationship
+
+  Examples
+  --------
+  >>> mean = (1,2)
+  >>> cov = [[1,0],[1,0]]
+  >>> x = multivariate_normal(mean,cov,(3,3))
+  >>> print x.shape
+  (3, 3, 2)
+
+  The following is probably true, given that 0.6 is roughly twice the
+  standard deviation:
+
+  >>> print list( (x[0,0,:] - mean) < 0.6 )
+  [True, True]
+
+  .. index:: random
+     :refguide: random;distributions, random;gauss
+
+  '''
+doc = NumpyDocString(doc_txt)
+
+
+def test_signature():
+    assert doc['Signature'].startswith('numpy.multivariate_normal(')
+    assert doc['Signature'].endswith('spam=None)')
+
+def test_summary():
+    assert doc['Summary'][0].startswith('Draw values')
+    assert doc['Summary'][-1].endswith('covariance.')
+
+def test_extended_summary():
+    assert doc['Extended Summary'][0].startswith('The multivariate normal')
+
+def test_parameters():
+    assert_equal(len(doc['Parameters']), 3)
+    assert_equal([n for n,_,_ in doc['Parameters']], ['mean','cov','shape'])
+
+    arg, arg_type, desc = doc['Parameters'][1]
+    assert_equal(arg_type, '(N, N) ndarray')
+    assert desc[0].startswith('Covariance matrix')
+    assert doc['Parameters'][0][-1][-2] == '   (1+2+3)/3'
+
+def test_other_parameters():
+    assert_equal(len(doc['Other Parameters']), 1)
+    assert_equal([n for n,_,_ in doc['Other Parameters']], ['spam'])
+    arg, arg_type, desc = doc['Other Parameters'][0]
+    assert_equal(arg_type, 'parrot')
+    assert desc[0].startswith('A parrot off its mortal coil')
+
+def test_returns():
+    assert_equal(len(doc['Returns']), 2)
+    arg, arg_type, desc = doc['Returns'][0]
+    assert_equal(arg, 'out')
+    assert_equal(arg_type, 'ndarray')
+    assert desc[0].startswith('The drawn samples')
+    assert desc[-1].endswith('distribution.')
+
+    arg, arg_type, desc = doc['Returns'][1]
+    assert_equal(arg, 'list of str')
+    assert_equal(arg_type, '')
+    assert desc[0].startswith('This is not a real')
+    assert desc[-1].endswith('anonymous return values.')
+
+def test_notes():
+    assert doc['Notes'][0].startswith('Instead')
+    assert doc['Notes'][-1].endswith('definite.')
+    assert_equal(len(doc['Notes']), 17)
+
+def test_references():
+    assert doc['References'][0].startswith('..')
+    assert doc['References'][-1].endswith('2001.')
+
+def test_examples():
+    assert doc['Examples'][0].startswith('>>>')
+    assert doc['Examples'][-1].endswith('True]')
+
+def test_index():
+    assert_equal(doc['index']['default'], 'random')
+    assert_equal(len(doc['index']), 2)
+    assert_equal(len(doc['index']['refguide']), 2)
+
+def non_blank_line_by_line_compare(a,b):
+    a = textwrap.dedent(a)
+    b = textwrap.dedent(b)
+    a = [l.rstrip() for l in a.split('\n') if l.strip()]
+    b = [l.rstrip() for l in b.split('\n') if l.strip()]
+    for n,line in enumerate(a):
+        if not line == b[n]:
+            raise AssertionError("Lines %s of a and b differ: "
+                                 "\n>>> %s\n<<< %s\n" %
+                                 (n,line,b[n]))
+def test_str():
+    non_blank_line_by_line_compare(str(doc),
+"""numpy.multivariate_normal(mean, cov, shape=None, spam=None)
+
+Draw values from a multivariate normal distribution with specified
+mean and covariance.
+
+The multivariate normal or Gaussian distribution is a generalisation
+of the one-dimensional normal distribution to higher dimensions.
+
+Parameters
+----------
+mean : (N,) ndarray
+    Mean of the N-dimensional distribution.
+
+    .. math::
+
+       (1+2+3)/3
+
+cov : (N, N) ndarray
+    Covariance matrix of the distribution.
+shape : tuple of ints
+    Given a shape of, for example, (m,n,k), m*n*k samples are
+    generated, and packed in an m-by-n-by-k arrangement.  Because
+    each sample is N-dimensional, the output shape is (m,n,k,N).
+
+Returns
+-------
+out : ndarray
+    The drawn samples, arranged according to `shape`.  If the
+    shape given is (m,n,...), then the shape of `out` is is
+    (m,n,...,N).
+
+    In other words, each entry ``out[i,j,...,:]`` is an N-dimensional
+    value drawn from the distribution.
+list of str
+    This is not a real return value.  It exists to test
+    anonymous return values.
+
+Other Parameters
+----------------
+spam : parrot
+    A parrot off its mortal coil.
+
+Raises
+------
+RuntimeError
+    Some error
+
+Warns
+-----
+RuntimeWarning
+    Some warning
+
+Warnings
+--------
+Certain warnings apply.
+
+See Also
+--------
+`some`_, `other`_, `funcs`_
+
+`otherfunc`_
+    relationship
+
+Notes
+-----
+Instead of specifying the full covariance matrix, popular
+approximations include:
+
+  - Spherical covariance (`cov` is a multiple of the identity matrix)
+  - Diagonal covariance (`cov` has non-negative elements only on the diagonal)
+
+This geometrical property can be seen in two dimensions by plotting
+generated data-points:
+
+>>> mean = [0,0]
+>>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis
+
+>>> x,y = multivariate_normal(mean,cov,5000).T
+>>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show()
+
+Note that the covariance matrix must be symmetric and non-negative
+definite.
+
+References
+----------
+.. [1] A. Papoulis, "Probability, Random Variables, and Stochastic
+       Processes," 3rd ed., McGraw-Hill Companies, 1991
+.. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification,"
+       2nd ed., Wiley, 2001.
+
+Examples
+--------
+>>> mean = (1,2)
+>>> cov = [[1,0],[1,0]]
+>>> x = multivariate_normal(mean,cov,(3,3))
+>>> print x.shape
+(3, 3, 2)
+
+The following is probably true, given that 0.6 is roughly twice the
+standard deviation:
+
+>>> print list( (x[0,0,:] - mean) < 0.6 )
+[True, True]
+
+.. index:: random
+   :refguide: random;distributions, random;gauss""")
+
+
+def test_sphinx_str():
+    sphinx_doc = SphinxDocString(doc_txt)
+    non_blank_line_by_line_compare(str(sphinx_doc),
+"""
+.. index:: random
+   single: random;distributions, random;gauss
+
+Draw values from a multivariate normal distribution with specified
+mean and covariance.
+
+The multivariate normal or Gaussian distribution is a generalisation
+of the one-dimensional normal distribution to higher dimensions.
+
+:Parameters:
+
+    **mean** : (N,) ndarray
+
+        Mean of the N-dimensional distribution.
+
+        .. math::
+
+           (1+2+3)/3
+
+    **cov** : (N, N) ndarray
+
+        Covariance matrix of the distribution.
+
+    **shape** : tuple of ints
+
+        Given a shape of, for example, (m,n,k), m*n*k samples are
+        generated, and packed in an m-by-n-by-k arrangement.  Because
+        each sample is N-dimensional, the output shape is (m,n,k,N).
+
+:Returns:
+
+    **out** : ndarray
+
+        The drawn samples, arranged according to `shape`.  If the
+        shape given is (m,n,...), then the shape of `out` is is
+        (m,n,...,N).
+
+        In other words, each entry ``out[i,j,...,:]`` is an N-dimensional
+        value drawn from the distribution.
+
+    list of str
+
+        This is not a real return value.  It exists to test
+        anonymous return values.
+
+:Other Parameters:
+
+    **spam** : parrot
+
+        A parrot off its mortal coil.
+
+:Raises:
+
+    **RuntimeError**
+
+        Some error
+
+:Warns:
+
+    **RuntimeWarning**
+
+        Some warning
+
+.. warning::
+
+    Certain warnings apply.
+
+.. seealso::
+
+    :obj:`some`, :obj:`other`, :obj:`funcs`
+
+    :obj:`otherfunc`
+        relationship
+
+.. rubric:: Notes
+
+Instead of specifying the full covariance matrix, popular
+approximations include:
+
+  - Spherical covariance (`cov` is a multiple of the identity matrix)
+  - Diagonal covariance (`cov` has non-negative elements only on the diagonal)
+
+This geometrical property can be seen in two dimensions by plotting
+generated data-points:
+
+>>> mean = [0,0]
+>>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis
+
+>>> x,y = multivariate_normal(mean,cov,5000).T
+>>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show()
+
+Note that the covariance matrix must be symmetric and non-negative
+definite.
+
+.. rubric:: References
+
+.. [1] A. Papoulis, "Probability, Random Variables, and Stochastic
+       Processes," 3rd ed., McGraw-Hill Companies, 1991
+.. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification,"
+       2nd ed., Wiley, 2001.
+
+.. only:: latex
+
+   [1]_, [2]_
+
+.. rubric:: Examples
+
+>>> mean = (1,2)
+>>> cov = [[1,0],[1,0]]
+>>> x = multivariate_normal(mean,cov,(3,3))
+>>> print x.shape
+(3, 3, 2)
+
+The following is probably true, given that 0.6 is roughly twice the
+standard deviation:
+
+>>> print list( (x[0,0,:] - mean) < 0.6 )
+[True, True]
+""")
+
+
+doc2 = NumpyDocString("""
+    Returns array of indices of the maximum values of along the given axis.
+
+    Parameters
+    ----------
+    a : {array_like}
+        Array to look in.
+    axis : {None, integer}
+        If None, the index is into the flattened array, otherwise along
+        the specified axis""")
+
+def test_parameters_without_extended_description():
+    assert_equal(len(doc2['Parameters']), 2)
+
+doc3 = NumpyDocString("""
+    my_signature(*params, **kwds)
+
+    Return this and that.
+    """)
+
+def test_escape_stars():
+    signature = str(doc3).split('\n')[0]
+    assert_equal(signature, 'my_signature(\*params, \*\*kwds)')
+
+doc4 = NumpyDocString(
+    """a.conj()
+
+    Return an array with all complex-valued elements conjugated.""")
+
+def test_empty_extended_summary():
+    assert_equal(doc4['Extended Summary'], [])
+
+doc5 = NumpyDocString(
+    """
+    a.something()
+
+    Raises
+    ------
+    LinAlgException
+        If array is singular.
+
+    Warns
+    -----
+    SomeWarning
+        If needed
+    """)
+
+def test_raises():
+    assert_equal(len(doc5['Raises']), 1)
+    name,_,desc = doc5['Raises'][0]
+    assert_equal(name,'LinAlgException')
+    assert_equal(desc,['If array is singular.'])
+
+def test_warns():
+    assert_equal(len(doc5['Warns']), 1)
+    name,_,desc = doc5['Warns'][0]
+    assert_equal(name,'SomeWarning')
+    assert_equal(desc,['If needed'])
+
+def test_see_also():
+    doc6 = NumpyDocString(
+    """
+    z(x,theta)
+
+    See Also
+    --------
+    func_a, func_b, func_c
+    func_d : some equivalent func
+    foo.func_e : some other func over
+             multiple lines
+    func_f, func_g, :meth:`func_h`, func_j,
+    func_k
+    :obj:`baz.obj_q`
+    :class:`class_j`: fubar
+        foobar
+    """)
+
+    assert len(doc6['See Also']) == 12
+    for func, desc, role in doc6['See Also']:
+        if func in ('func_a', 'func_b', 'func_c', 'func_f',
+                    'func_g', 'func_h', 'func_j', 'func_k', 'baz.obj_q'):
+            assert(not desc)
+        else:
+            assert(desc)
+
+        if func == 'func_h':
+            assert role == 'meth'
+        elif func == 'baz.obj_q':
+            assert role == 'obj'
+        elif func == 'class_j':
+            assert role == 'class'
+        else:
+            assert role is None
+
+        if func == 'func_d':
+            assert desc == ['some equivalent func']
+        elif func == 'foo.func_e':
+            assert desc == ['some other func over', 'multiple lines']
+        elif func == 'class_j':
+            assert desc == ['fubar', 'foobar']
+
+def test_see_also_print():
+    class Dummy(object):
+        """
+        See Also
+        --------
+        func_a, func_b
+        func_c : some relationship
+                 goes here
+        func_d
+        """
+        pass
+
+    obj = Dummy()
+    s = str(FunctionDoc(obj, role='func'))
+    assert(':func:`func_a`, :func:`func_b`' in s)
+    assert('    some relationship' in s)
+    assert(':func:`func_d`' in s)
+
+doc7 = NumpyDocString("""
+
+        Doc starts on second line.
+
+        """)
+
+def test_empty_first_line():
+    assert doc7['Summary'][0].startswith('Doc starts')
+
+
+def test_no_summary():
+    str(SphinxDocString("""
+    Parameters
+    ----------"""))
+
+
+def test_unicode():
+    doc = SphinxDocString("""
+    öäöäöäöäöåååå
+
+    öäöäöäööäååå
+
+    Parameters
+    ----------
+    ååå : äää
+        ööö
+
+    Returns
+    -------
+    ååå : ööö
+        äää
+
+    """)
+    assert isinstance(doc['Summary'][0], str)
+    assert doc['Summary'][0] == 'öäöäöäöäöåååå'
+
+def test_plot_examples():
+    cfg = dict(use_plots=True)
+
+    doc = SphinxDocString("""
+    Examples
+    --------
+    >>> import matplotlib.pyplot as plt
+    >>> plt.plot([1,2,3],[4,5,6])
+    >>> plt.show()
+    """, config=cfg)
+    assert 'plot::' in str(doc), str(doc)
+
+    doc = SphinxDocString("""
+    Examples
+    --------
+    .. plot::
+
+       import matplotlib.pyplot as plt
+       plt.plot([1,2,3],[4,5,6])
+       plt.show()
+    """, config=cfg)
+    assert str(doc).count('plot::') == 1, str(doc)
+
+def test_class_members():
+
+    class Dummy(object):
+        """
+        Dummy class.
+
+        """
+        def spam(self, a, b):
+            """Spam\n\nSpam spam."""
+            pass
+        def ham(self, c, d):
+            """Cheese\n\nNo cheese."""
+            pass
+        @property
+        def spammity(self):
+            """Spammity index"""
+            return 0.95
+
+        class Ignorable(object):
+            """local class, to be ignored"""
+            pass
+
+    for cls in (ClassDoc, SphinxClassDoc):
+        doc = cls(Dummy, config=dict(show_class_members=False))
+        assert 'Methods' not in str(doc), (cls, str(doc))
+        assert 'spam' not in str(doc), (cls, str(doc))
+        assert 'ham' not in str(doc), (cls, str(doc))
+        assert 'spammity' not in str(doc), (cls, str(doc))
+        assert 'Spammity index' not in str(doc), (cls, str(doc))
+
+        doc = cls(Dummy, config=dict(show_class_members=True))
+        assert 'Methods' in str(doc), (cls, str(doc))
+        assert 'spam' in str(doc), (cls, str(doc))
+        assert 'ham' in str(doc), (cls, str(doc))
+        assert 'spammity' in str(doc), (cls, str(doc))
+
+        if cls is SphinxClassDoc:
+            assert '.. autosummary::' in str(doc), str(doc)
+        else:
+            assert 'Spammity index' in str(doc), str(doc)
+
+def test_duplicate_signature():
+    # Duplicate function signatures occur e.g. in ufuncs, when the
+    # automatic mechanism adds one, and a more detailed comes from the
+    # docstring itself.
+
+    doc = NumpyDocString(
+    """
+    z(x1, x2)
+
+    z(a, theta)
+    """)
+
+    assert doc['Signature'].strip() == 'z(a, theta)'
+
+
+class_doc_txt = """
+    Foo
+
+    Parameters
+    ----------
+    f : callable ``f(t, y, *f_args)``
+        Aaa.
+    jac : callable ``jac(t, y, *jac_args)``
+        Bbb.
+
+    Attributes
+    ----------
+    t : float
+        Current time.
+    y : ndarray
+        Current variable values.
+
+    Methods
+    -------
+    a
+    b
+    c
+
+    Examples
+    --------
+    For usage examples, see `ode`.
+"""
+
+def test_class_members_doc():
+    doc = ClassDoc(None, class_doc_txt)
+    non_blank_line_by_line_compare(str(doc),
+    """
+    Foo
+
+    Parameters
+    ----------
+    f : callable ``f(t, y, *f_args)``
+        Aaa.
+    jac : callable ``jac(t, y, *jac_args)``
+        Bbb.
+
+    Examples
+    --------
+    For usage examples, see `ode`.
+
+    Attributes
+    ----------
+    t : float
+        Current time.
+    y : ndarray
+        Current variable values.
+
+    Methods
+    -------
+    a
+
+    b
+
+    c
+
+    .. index::
+
+    """)
+
+def test_class_members_doc_sphinx():
+    doc = SphinxClassDoc(None, class_doc_txt)
+    non_blank_line_by_line_compare(str(doc),
+    """
+    Foo
+
+    :Parameters:
+
+        **f** : callable ``f(t, y, *f_args)``
+
+            Aaa.
+
+        **jac** : callable ``jac(t, y, *jac_args)``
+
+            Bbb.
+
+    .. rubric:: Examples
+
+    For usage examples, see `ode`.
+
+    .. rubric:: Attributes
+
+    ===  ==========
+      t  (float) Current time.
+      y  (ndarray) Current variable values.
+    ===  ==========
+
+    .. rubric:: Methods
+
+    ===  ==========
+      a
+      b
+      c
+    ===  ==========
+
+    """)
+
+if __name__ == "__main__":
+    import nose
+    nose.run()
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/tests/test_linkcode.py b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_linkcode.py
new file mode 100644
index 0000000..340166a
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_linkcode.py
@@ -0,0 +1,5 @@
+from __future__ import division, absolute_import, print_function
+
+import numpydoc.linkcode
+
+# No tests at the moment...
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/tests/test_phantom_import.py b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_phantom_import.py
new file mode 100644
index 0000000..80fae08
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_phantom_import.py
@@ -0,0 +1,12 @@
+from __future__ import division, absolute_import, print_function
+
+import sys
+from nose import SkipTest
+
+def test_import():
+    if sys.version_info[0] >= 3:
+        raise SkipTest("phantom_import not ported to Py3")
+
+    import numpydoc.phantom_import
+
+# No tests at the moment...
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/tests/test_plot_directive.py b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_plot_directive.py
new file mode 100644
index 0000000..1ea1076
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_plot_directive.py
@@ -0,0 +1,11 @@
+from __future__ import division, absolute_import, print_function
+
+import sys
+from nose import SkipTest
+
+def test_import():
+    if sys.version_info[0] >= 3:
+        raise SkipTest("plot_directive not ported to Python 3 (use the one from Matplotlib instead)")
+    import numpydoc.plot_directive
+
+# No tests at the moment...
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/tests/test_traitsdoc.py b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_traitsdoc.py
new file mode 100644
index 0000000..fe5078c
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/tests/test_traitsdoc.py
@@ -0,0 +1,11 @@
+from __future__ import division, absolute_import, print_function
+
+import sys
+from nose import SkipTest
+
+def test_import():
+    if sys.version_info[0] >= 3:
+        raise SkipTest("traitsdoc not ported to Python3")
+    import numpydoc.traitsdoc
+
+# No tests at the moment...
diff --git a/doc/source/sphinxext/numpydoc/numpydoc/traitsdoc.py b/doc/source/sphinxext/numpydoc/numpydoc/traitsdoc.py
new file mode 100644
index 0000000..596c54e
--- /dev/null
+++ b/doc/source/sphinxext/numpydoc/numpydoc/traitsdoc.py
@@ -0,0 +1,142 @@
+"""
+=========
+traitsdoc
+=========
+
+Sphinx extension that handles docstrings in the Numpy standard format, [1]
+and support Traits [2].
+
+This extension can be used as a replacement for ``numpydoc`` when support
+for Traits is required.
+
+.. [1] http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard
+.. [2] http://code.enthought.com/projects/traits/
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import inspect
+import os
+import pydoc
+import collections
+
+from . import docscrape
+from . import docscrape_sphinx
+from .docscrape_sphinx import SphinxClassDoc, SphinxFunctionDoc, SphinxDocString
+
+from . import numpydoc
+
+from . import comment_eater
+
+class SphinxTraitsDoc(SphinxClassDoc):
+    def __init__(self, cls, modulename='', func_doc=SphinxFunctionDoc):
+        if not inspect.isclass(cls):
+            raise ValueError("Initialise using a class. Got %r" % cls)
+        self._cls = cls
+
+        if modulename and not modulename.endswith('.'):
+            modulename += '.'
+        self._mod = modulename
+        self._name = cls.__name__
+        self._func_doc = func_doc
+
+        docstring = pydoc.getdoc(cls)
+        docstring = docstring.split('\n')
+
+        # De-indent paragraph
+        try:
+            indent = min(len(s) - len(s.lstrip()) for s in docstring
+                         if s.strip())
+        except ValueError:
+            indent = 0
+
+        for n,line in enumerate(docstring):
+            docstring[n] = docstring[n][indent:]
+
+        self._doc = docscrape.Reader(docstring)
+        self._parsed_data = {
+            'Signature': '',
+            'Summary': '',
+            'Description': [],
+            'Extended Summary': [],
+            'Parameters': [],
+            'Returns': [],
+            'Raises': [],
+            'Warns': [],
+            'Other Parameters': [],
+            'Traits': [],
+            'Methods': [],
+            'See Also': [],
+            'Notes': [],
+            'References': '',
+            'Example': '',
+            'Examples': '',
+            'index': {}
+            }
+
+        self._parse()
+
+    def _str_summary(self):
+        return self['Summary'] + ['']
+
+    def _str_extended_summary(self):
+        return self['Description'] + self['Extended Summary'] + ['']
+
+    def __str__(self, indent=0, func_role="func"):
+        out = []
+        out += self._str_signature()
+        out += self._str_index() + ['']
+        out += self._str_summary()
+        out += self._str_extended_summary()
+        for param_list in ('Parameters', 'Traits', 'Methods',
+                           'Returns','Raises'):
+            out += self._str_param_list(param_list)
+        out += self._str_see_also("obj")
+        out += self._str_section('Notes')
+        out += self._str_references()
+        out += self._str_section('Example')
+        out += self._str_section('Examples')
+        out = self._str_indent(out,indent)
+        return '\n'.join(out)
+
+def looks_like_issubclass(obj, classname):
+    """ Return True if the object has a class or superclass with the given class
+    name.
+
+    Ignores old-style classes.
+    """
+    t = obj
+    if t.__name__ == classname:
+        return True
+    for klass in t.__mro__:
+        if klass.__name__ == classname:
+            return True
+    return False
+
+def get_doc_object(obj, what=None, config=None):
+    if what is None:
+        if inspect.isclass(obj):
+            what = 'class'
+        elif inspect.ismodule(obj):
+            what = 'module'
+        elif isinstance(obj, collections.Callable):
+            what = 'function'
+        else:
+            what = 'object'
+    if what == 'class':
+        doc = SphinxTraitsDoc(obj, '', func_doc=SphinxFunctionDoc, config=config)
+        if looks_like_issubclass(obj, 'HasTraits'):
+            for name, trait, comment in comment_eater.get_class_traits(obj):
+                # Exclude private traits.
+                if not name.startswith('_'):
+                    doc['Traits'].append((name, trait, comment.splitlines()))
+        return doc
+    elif what in ('function', 'method'):
+        return SphinxFunctionDoc(obj, '', config=config)
+    else:
+        return SphinxDocString(pydoc.getdoc(obj), config=config)
+
+def setup(app):
+    # init numpydoc
+    numpydoc.setup(app, get_doc_object)
+
diff --git a/emperor/_pandas.py b/emperor/_pandas.py
new file mode 100644
index 0000000..e2925f7
--- /dev/null
+++ b/emperor/_pandas.py
@@ -0,0 +1,103 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+import numpy as np
+import pandas as pd
+
+from emperor.core import Emperor
+from skbio import OrdinationResults
+
+
+def scatterplot(df, x=None, y=None, z=None, remote=True):
+    """Create an Emperor scatter plot from a Pandas DataFrame
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        Pandas DataFrame with the data to display, this includes both
+        *metadata* and *coordinates* to position the samples in a 3D space.
+    x, y, z : str, optional
+        Column names in `df`, to use as first (``x``), second (``y``) and third
+        (``z``) axes in the visualization. If these are not specified, axes
+        are chosen according to the variance (in decremental order).
+    remote : bool, optional
+        Whether the JavaScript resources should be loaded locally or from
+        GitHub. Defaults to ``True``.
+
+    Returns
+    -------
+    emperor.core.Emperor
+        Emperor object with the numerical data as the `ordination` attribute
+        and the entire DataFrame as the `mf` attribute.
+
+    Raises
+    ------
+    ValueError
+        If `df` is not a PandasDataFrame
+        If `x`, `y` or `z` are missing from `df` or if they are not numeric
+        columns.
+        If after removing rows with missing data there are fewer than 3
+        samples.
+
+    Notes
+    -----
+    If a row has missing data, that data point will be removed from the
+    visualization.
+
+    See Also
+    --------
+    emperor.core.Emperor
+    """
+
+    if not isinstance(df, pd.DataFrame):
+        raise ValueError("The argument is not a Pandas DataFrame")
+
+    for col in [z, y, x]:
+        if col is None:
+            continue
+
+        if col not in df.columns:
+            raise ValueError("'%s' is not a column in the DataFrame" % col)
+
+        if not np.issubdtype(df[col].dtype, np.number):
+            raise ValueError("'%s' is not a numeric column" % col)
+
+    # remove NAs
+    samples = df.select_dtypes(include=[np.number]).copy()
+    samples.dropna(axis=0, how='any', inplace=True)
+
+    if len(samples.columns) < 3:
+        raise ValueError("Not enough data to plot")
+
+    # sort columns by variance
+    variance = samples.var().sort_values(ascending=False)
+    samples = samples[variance.index]
+
+    # re-order x, y and z
+    ordered = samples.columns.tolist()
+    for col in [z, y, x]:
+        if col is not None:
+            ordered.remove(col)
+            ordered = [col] + ordered
+    samples = samples[ordered]
+
+    # match up the metadata and coordinates
+    df = df.loc[samples.index]
+
+    ores = OrdinationResults(short_method_name='', long_method_name='',
+                             eigvals=np.zeros_like(samples.columns),
+                             samples=samples, proportion_explained=variance)
+
+    df.index.name = '#SampleID'
+
+    # HACK: scale the position of the samples to fit better within the screen
+    ores.samples = ores.samples / ores.samples.max(axis=0)
+
+    return Emperor(ores, df, dimensions=len(ores.samples.columns),
+                   remote=remote)
diff --git a/emperor/core.py b/emperor/core.py
new file mode 100644
index 0000000..1df732b
--- /dev/null
+++ b/emperor/core.py
@@ -0,0 +1,332 @@
+r"""
+Emperor 3D PCoA viewer (:mod:`emperor.core`)
+============================================
+
+This module provides an Object to interact and visualize an Emperor plot
+from the IPython notebook.
+
+.. currentmodule:: emperor.core
+
+Classes
+-------
+.. autosummary::
+    :toctree: generated/
+
+    Emperor
+"""
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+from os.path import join, basename
+from distutils.dir_util import copy_tree
+import numpy as np
+
+from jinja2 import FileSystemLoader
+from jinja2.environment import Environment
+
+from emperor.util import (get_emperor_support_files_dir,
+                          validate_and_process_custom_axes)
+from emperor.qiime_backports.make_3d_plots import (get_custom_coords,
+                                                   remove_nans,
+                                                   scale_custom_coords)
+
+# we are going to use this remote location to load external resources
+REMOTE_URL = ('https://cdn.rawgit.com/biocore/emperor/new-api/emperor'
+              '/support_files')
+LOCAL_URL = "/nbextensions/emperor/support_files"
+
+STYLE_PATH = join(get_emperor_support_files_dir(), 'templates',
+                  'style-template.html')
+LOGIC_PATH = join(get_emperor_support_files_dir(), 'templates',
+                  'logic-template.html')
+
+STANDALONE_PATH = join(get_emperor_support_files_dir(), 'templates',
+                       'standalone-template.html')
+JUPYTER_PATH = join(get_emperor_support_files_dir(), 'templates',
+                    'jupyter-template.html')
+
+
+class Emperor(object):
+    """Display principal coordinates analysis plots
+
+    Use this object to interactively display a PCoA plot using the Emperor
+    GUI. IPython provides a rich display system that will let you display a
+    plot inline, without the need of creating a temprorary file or having to
+    write to disk.
+
+    Parameters
+    ----------
+    ordination: skbio.OrdinationResults
+        Object containing the computed values for an ordination method in
+        scikit-bio.
+    mapping_file: pd.DataFrame
+        DataFrame object with the metadata associated to the samples in the
+        ``ordination`` object, should have an index set and it should match the
+        identifiers in the ``ordination`` object.
+    dimensions: int, optional
+        Number of dimensions to keep from the ordination data, defaults to 5.
+    remote: bool or str, optional
+        This parameter can have one of the following three behaviors according
+        to the value: (1) ``str`` - load the resources from a user-specified
+        remote location, (2) ``False`` - load the resources from the
+        nbextensions folder in the Jupyter installation or (3) ``True`` - load
+        the resources from the GitHub repository. This parameter defaults to
+        ``True``. See the Notes section for more information.
+
+    Examples
+    --------
+    Create an Emperor object and display it from the Jupyter notebook:
+
+    >>> import pandas as pd, numpy as np
+    >>> from emperor import Emperor
+    >>> from skbio import OrdinationResults
+
+    Ordination plots are almost invariantly associated with a set of data, that
+    relates each sample to its scientific context, we refer to this as the
+    *sample metadata*, and represent it using Pandas DataFrames. For this
+    example we will need some metadata, we start by creating our metadata
+    object:
+
+    >>> data = [['PC.354', 'Control', '20061218', 'Control_mouse_I.D._354'],
+    ... ['PC.355', 'Control', '20061218', 'Control_mouse_I.D._355'],
+    ... ['PC.356', 'Control', '20061126', 'Control_mouse_I.D._356'],
+    ... ['PC.481', 'Control', '20070314', 'Control_mouse_I.D._481'],
+    ... ['PC.593', 'Control', '20071210', 'Control_mouse_I.D._593'],
+    ... ['PC.607', 'Fast', '20071112', 'Fasting_mouse_I.D._607'],
+    ... ['PC.634', 'Fast', '20080116', 'Fasting_mouse_I.D._634'],
+    ... ['PC.635', 'Fast', '20080116', 'Fasting_mouse_I.D._635'],
+    ... ['PC.636', 'Fast', '20080116', 'Fasting_mouse_I.D._636']]
+    >>> columns = ['SampleID', 'Treatment', 'DOB', 'Description']
+    >>> mf = pd.DataFrame(columns=columns, data=data)
+
+    Before we can use this mapping file in Emperor, we should set the index
+    to be `SampleID`.
+
+    >>> mf.set_index('SampleID', inplace=True)
+
+    Then let's create some artificial ordination data:
+
+    >>> ids = ('PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593',
+    ...             'PC.355', 'PC.607', 'PC.634')
+    >>> eigvals = np.array([0.47941212, 0.29201496, 0.24744925,
+    ...                     0.20149607, 0.18007613, 0.14780677,
+    ...                     0.13579593, 0.1122597, 0.])
+    >>> eigvals = pd.Series(data=eigvals, index=ids)
+    >>> n = eigvals.shape[0]
+    >>> samples = np.random.randn(n, n)
+    >>> samples = pd.DataFrame(data=site, index=ids)
+    >>> p_explained = np.array([0.26688705, 0.1625637, 0.13775413, 0.11217216,
+    ...                         0.10024775, 0.08228351, 0.07559712, 0.06249458,
+    ...                         0.])
+    >>> p_explained = pd.Series(data=p_explained, index=ids)
+
+    And encapsulate it inside an ``OrdinationResults`` object:
+
+    >>> ores = OrdinationResults(eigvals, samples=samples,
+    ...                          proportion_explained=p_explained)
+
+    Finally import the Emperor object and display it using Jupyter, note that
+    this call will have no effect under a regular Python session:
+
+    >>> Emperor(ores, mf)
+
+    Notes
+    -----
+    This object currently does not support the full range of actions that the
+    GUI does support and should be considered experimental at the moment.
+
+    The ``remote`` parameter is intended for different use-cases, you should
+    use the first option "(1) - URL" when you want to load the data from a
+    location different than the GitHub repository or your Jupyter notebook
+    resources i.e. a custom URL. The second option "(2) - ``False``" loads
+    resources from your local Jupyter installation, note that you **need** to
+    execute ``nbinstall`` at least once or the application will error, this
+    option is ideal for developers modifying the JavaScript source code, and in
+    environments of limited internet connection. Finally, the third option "(3)
+    - ``True``" should be used if you intend to embed an Emperor plot in a
+    notebook and then publish it using http://nbviewer.jupyter.org.
+
+    Raises
+    ------
+    ValueError
+        If the remote argument is not of ``bool`` or ``str`` type.
+
+    References
+    ----------
+    .. [1] EMPeror: a tool for visualizing high-throughput microbial community
+       data Vazquez-Baeza Y, Pirrung M, Gonzalez A, Knight R.  Gigascience.
+       2013 Nov 26;2(1):16.
+
+    """
+    def __init__(self, ordination, mapping_file, dimensions=5, remote=True):
+        self.ordination = ordination
+
+        self.mf = mapping_file.copy()
+
+        # filter all metadata that we may have for which we don't have any
+        # coordinates this also ensures that the coordinates are in the
+        # same order as the metadata
+        self.mf = self.mf.loc[ordination.samples.index]
+
+        self._html = None
+
+        if ordination.proportion_explained.shape[0] < dimensions:
+            self.dimensions = ordination.proportion_explained.shape[0]
+        else:
+            self.dimensions = dimensions
+
+        if isinstance(remote, bool):
+            if remote:
+                self.base_url = REMOTE_URL
+            else:
+                self.base_url = LOCAL_URL
+        elif isinstance(remote, str):
+            self.base_url = remote
+        else:
+            raise ValueError("Unsupported type for `remote` argument, should "
+                             "be a bool or str")
+
+    def __str__(self):
+        return self.make_emperor()
+
+    def _repr_html_(self):
+        """Used to display a plot in the Jupyter notebook"""
+
+        # we import here as IPython shouldn't be a dependency of Emperor
+        # however if this method is called it will be from an IPython notebook
+        # otherwise the developer is responsible for calling this method
+        from IPython.display import display, HTML
+
+        return display(HTML(str(self)))
+
+    def copy_support_files(self, target=None):
+        """Copies the support files to a target directory
+
+        Parameters
+        ----------
+        target : str
+            The path where resources should be copied to. By default it copies
+            the files to ``self.base_url``.
+        """
+        if target is None:
+            target = self.base_url
+
+        # copy the required resources
+        copy_tree(get_emperor_support_files_dir(), target)
+
+    def make_emperor(self, standalone=False, custom_axes=None):
+        """Build an emperor plot
+
+        Parameters
+        ----------
+        standalone : bool
+            Whether or not the produced plot should be a standalone HTML file.
+        custom_axes : list of str, optional
+            Custom axes to embed in the ordination.
+
+        Returns
+        -------
+        str
+            Formatted emperor plot.
+
+        Raises
+        ------
+        KeyError
+            If one or more of the ``custom_axes`` names are not present in the
+            sample information.
+        ValueError
+            If any of the ``custom_axes`` have non-numeric values.
+
+        Notes
+        -----
+        The ``standalone`` argument is intended for the different use-cases
+        that Emperor can have, either as an embedded widget that lives inside,
+        for example, the Jupyter notebook, or alternatively as an HTML file
+        that refers to resources locally. In this case you will need to copy
+        the support files by calling the ``copy_support_files`` method.
+
+        See Also
+        --------
+        emperor.core.Emperor.copy_support_files
+        """
+
+        # based on: http://stackoverflow.com/a/6196098
+        loader = FileSystemLoader(join(get_emperor_support_files_dir(),
+                                       'templates'))
+
+        if standalone:
+            main_path = basename(STANDALONE_PATH)
+        else:
+            main_path = basename(JUPYTER_PATH)
+        env = Environment(loader=loader)
+
+        main_template = env.get_template(main_path)
+
+        # there's a bug in old versions of Pandas that won't allow us to rename
+        # a DataFrame's index, newer versions i.e 0.18 work just fine but 0.14
+        # would overwrite the name and simply set it as None
+        if self.mf.index.name is None:
+            index_name = 'SampleID'
+        else:
+            index_name = self.mf.index.name
+
+        # format the metadata
+        headers = list(map(str, [index_name] + self.mf.columns.tolist()))
+        metadata = self.mf.apply(lambda x: [str(x.name)] +
+                                 x.astype('str').tolist(),
+                                 axis=1).values.tolist()
+
+        # format the coordinates
+        d = self.dimensions
+        pct_var = (self.ordination.proportion_explained[:d] * 100).tolist()
+        coords = self.ordination.samples.values[:, :d].tolist()
+        names = self.ordination.samples.columns[:d].tolist()
+
+        # avoid unicode strings
+        coord_ids = list(map(str, self.mf.index.tolist()))
+
+        # TODO: This will be removed once the custom axes creation is moved to
+        # the graphical user interface i.e. to the Axes tab.
+        if custom_axes:
+            mf = validate_and_process_custom_axes(self.mf, custom_axes)
+
+            data = mf.apply(lambda x: [x.name] + x.tolist(),
+                            axis=1).values.tolist()
+
+            # vestigial qiime structures for metadata and coordinates
+            mapping_file = [headers] + data
+            coords_file = [coord_ids, coords]
+
+            # sequence ported from qiime/scripts/make_3d_plots.py @ 9115351
+            get_custom_coords(custom_axes, mapping_file, coords_file)
+            remove_nans(coords_file)
+            scale_custom_coords(custom_axes, coords_file)
+
+            # arguments are modified, so put them back out
+            _, coords = coords_file
+            coords = coords.tolist()
+
+            # custom axes are assigned -1 percent explained
+            pct_var = ([-1] * len(custom_axes)) + pct_var
+            names = custom_axes + names
+
+        # yes, we could have used UUID, but we couldn't find an easier way to
+        # test that deterministically and with this approach we can seed the
+        # random number generator and test accordingly
+        plot_id = 'emperor-notebook-' + str(hex(np.random.randint(2**32)))
+
+        plot = main_template.render(coords_ids=coord_ids, coords=coords,
+                                    pct_var=pct_var, md_headers=headers,
+                                    metadata=metadata, base_url=self.base_url,
+                                    plot_id=plot_id,
+                                    logic_template_path=basename(LOGIC_PATH),
+                                    style_template_path=basename(STYLE_PATH),
+                                    axes_names=names)
+
+        return plot
diff --git a/emperor/parse.py b/emperor/parse.py
new file mode 100644
index 0000000..1d07926
--- /dev/null
+++ b/emperor/parse.py
@@ -0,0 +1,43 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+from skbio import OrdinationResults
+from skbio.io import FileFormatError, IOSourceError
+
+from emperor.qiime_backports.parse import parse_coords as qiime_parse_coords
+
+
+def parse_coords(lines):
+    """Parse skbio's ordination results file into  coords, labels, eigvals,
+        pct_explained.
+
+    Returns:
+    - list of sample labels in order
+    - array of coords (rows = samples, cols = axes in descending order)
+    - list of eigenvalues
+    - list of percent variance explained
+
+    For the file format check
+    skbio.stats.ordination.OrdinationResults.read
+
+    Strategy: read the file using skbio's parser and return the objects
+              we want
+    """
+    try:
+        pcoa_results = OrdinationResults.read(lines)
+        return (pcoa_results.samples.index.tolist(),
+                pcoa_results.samples.values, pcoa_results.eigvals.values,
+                pcoa_results.proportion_explained.values)
+    except (FileFormatError, IOSourceError):
+        try:
+            lines.seek(0)
+        except AttributeError:
+            # looks like we have a list of lines, not a file-like object
+            pass
+        return qiime_parse_coords(lines)
diff --git a/emperor/pycogent_backports/__init__.py b/emperor/pycogent_backports/__init__.py
deleted file mode 100644
index 6c64933..0000000
--- a/emperor/pycogent_backports/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-
-__author__ = "Emperor Development Team"
-__copyright__ = "Copyright 2013, The Emperor Project"
-__credits__ = ["Yoshiki Vazquez Baeza"] 
-__license__ = "BSD"
-__version__ = "0.9.3"
-__maintainer__ = "Yoshiki Vazquez Baeza"
-__email__ = "yoshiki89 at gmail.com"
-__status__ = "Release"
-
-__all__ = ['procrustes']
diff --git a/emperor/pycogent_backports/procrustes.py b/emperor/pycogent_backports/procrustes.py
deleted file mode 100644
index 8de5fbf..0000000
--- a/emperor/pycogent_backports/procrustes.py
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/env python
-"""Procrustes analysis.  Main fn: procrustes
-
-See for example: 
-Principles of Multivariate analysis, by Krzanowski
-"""
-
-from numpy.linalg import svd
-from numpy import (array, sqrt, sum, zeros, trace, dot, transpose,
-    divide, square, subtract, shape, any, abs, mean)
-from numpy import append as numpy_append
-
-__author__ = "Justin Kuczynski"
-__copyright__ = "Copyright 2007-2012, The Cogent Project"
-__credits__ = ["Justin Kuczynski"]
-__license__ = "BSD"
-__version__ = "1.5.3-dev"
-__maintainer__ = "Justin Kuczynski"
-__email__ = "justinak at gmail.com"
-__status__ = "Production"
-
-def procrustes(data1, data2):
-    """Procrustes analysis, a similarity test for two data sets.
-    
-    Each input matrix is a set of points or vectors (the rows of the matrix)
-    The dimension of the space is the number of columns of each matrix.
-    Given two identially sized matrices, procrustes standardizes both
-    such that:
-    - trace(AA') = 1  (A' is the transpose, and the product is
-    a standard matrix product).
-    - Both sets of points are centered around the origin
-    
-    Procrustes then applies the optimal transform to the second matrix
-    (including scaling/dilation, rotations, and reflections) to minimize
-    M^2 = sum(square(mtx1 - mtx2)), or the sum of the squares of the pointwise
-    differences between the two input datasets
-    
-    If two data sets have different dimensionality (different number of
-    columns), simply add columns of zeros the the smaller of the two.
-    
-    This function was not designed to handle datasets with different numbers of
-    datapoints (rows)
-    
-    Arguments:
-        - data1: matrix, n rows represent points in k (columns) space
-        data1 is the reference data, after it is standardised, the data from
-        data2 will be transformed to fit the pattern in data1
-        - data2: n rows of data in k space to be fit to data1.  Must be the 
-        same shape (numrows, numcols) as data1
-        - both must have >1 unique points
-        
-    Returns:
-        - mtx1: a standardized version of data1
-        - mtx2: the orientation of data2 that best fits data1.
-        centered, but not necessarily trace(mtx2*mtx2') = 1
-        - disparity: a metric for the dissimilarity of the two datasets,
-        disparity = M^2 defined above
-        
-    Notes:
-        - The disparity should not depend on the order of the input matrices, 
-        but the output matrices will, as only the first output matrix is
-        guaranteed to be scaled such that trace(AA') = 1.
-        - duplicate datapoints are generally ok, duplicating a data point will
-        increase it's effect on the procrustes fit.
-        - the disparity scales as the number of points per input matrix
-        
-    
-    """
-    SMALL_NUM = 1e-6 # used to check for zero values in added dimension
-    
-    # make local copies
-#     mtx1 = array(data1.copy(),'d')
-#     mtx2 = array(data2.copy(),'d')
-    num_rows, num_cols = shape(data1)
-    if (num_rows, num_cols) != shape(data2):
-        raise ValueError("input matrices must be of same shape")
-    if (num_rows == 0 or num_cols == 0):
-        raise ValueError("input matrices must be >0 rows, >0 cols")
-        
-    
-    # add a dimension to allow reflections (rotations in n + 1 dimensions)
-    mtx1 = numpy_append(data1, zeros((num_rows, 1)), 1)
-    mtx2 = numpy_append(data2, zeros((num_rows, 1)), 1)
-    
-    # standardize each matrix
-    mtx1 = center(mtx1)
-    mtx2 = center(mtx2)
-    
-    if ((not any(mtx1)) or (not any(mtx2))):
-        raise ValueError("input matrices must contain >1 unique points")
-
-    mtx1 = normalize(mtx1)
-    mtx2 = normalize(mtx2)
-    
-       
-    # transform mtx2 to minimize disparity (sum( (mtx1[i,j] - mtx2[i,j])^2) )
-    mtx2 = match_points(mtx1, mtx2)
-    
-    # WARNING: I haven't proven that after matching the matrices, no point has
-    # a nonzero component in the added dimension.  I believe it is true,
-    # though, since the unchanged matrix has no points extending into 
-    # that dimension
-    
-    if any(abs(mtx2[:,-1]) > SMALL_NUM):
-        raise StandardError("we have accidentially added a dimension to \
-the matrix, and the vectors have nonzero components in that dimension")
-    
-    # strip extra dimension which was added to allow reflections
-    mtx1 = mtx1[:,:-1]
-    mtx2 = mtx2[:,:-1]
-    
-    disparity = get_disparity(mtx1, mtx2)
-    
-    return mtx1, mtx2, disparity
-    
-def center(mtx):
-    """translate all data (rows of the matrix) to center on the origin
-    
-    returns a shifted version of the input data.  The new matrix is such that
-    the center of mass of the row vectors is centered at the origin.  
-    Returns a numpy float ('d') array
-    """
-    result = array(mtx, 'd')
-    result -= mean(result, 0) 
-    # subtract each column's mean from each element in that column
-    return result
-
-def normalize(mtx):
-    """change scaling of data (in rows) such that trace(mtx*mtx') = 1
-    
-    mtx' denotes the transpose of mtx """
-    result = array(mtx, 'd')
-    num_pts, num_dims = shape(result)
-    mag = trace(dot(result, transpose(result)))
-    norm = sqrt(mag)
-    result /= norm
-    return result
-
-def match_points(mtx1, mtx2):
-    """returns a transformed mtx2 that matches mtx1.
-    
-    returns a new matrix which is a transform of mtx2.  Scales and rotates
-    a copy of mtx 2.  See procrustes docs for details.
-    """
-    u,s,vh = svd(dot(transpose(mtx1), mtx2))
-    q = dot(transpose(vh), transpose(u))
-    new_mtx2 = dot(mtx2, q)
-    new_mtx2 *= sum(s)
-    
-    return new_mtx2
-
-def get_disparity(mtx1, mtx2):
-    """ returns a measure of the dissimilarity between two data sets
-    
-    returns M^2 = sum(square(mtx1 - mtx2)), the pointwise sum of squared
-    differences"""
-    return(sum(square(mtx1 - mtx2)))
diff --git a/emperor/support_files/README.md b/emperor/support_files/README.md
new file mode 100644
index 0000000..b3c8fa1
--- /dev/null
+++ b/emperor/support_files/README.md
@@ -0,0 +1,8 @@
+# Emperor's resources
+
+The organization of this directory should be as follows:
+
+- `js/` should contain only JavaScript source code from Emperor.
+- `css/` should contain only CSS source code from Emperor.
+- `img/` should contain images that are only by Emperor.
+- `vendor/` should contain any third party code used in the project. If it is a JavaScript file the files should live in `vendor/js/` and if it is a CSS file the files should live in `vendor/css/`.
diff --git a/emperor/support_files/css/colorPicker.css b/emperor/support_files/css/colorPicker.css
deleted file mode 100755
index b16b98c..0000000
--- a/emperor/support_files/css/colorPicker.css
+++ /dev/null
@@ -1,31 +0,0 @@
-div.colorPicker-picker {
-  height: 16px;
-  width: 16px;
-  padding: 0 !important;
-  border: 1px solid #ccc;
-  background: url(arrow.gif) no-repeat top right;
-  cursor: pointer;
-  line-height: 16px;
-}
-
-div.colorPicker-palette {
-  width: 110px;
-  position: absolute;
-  border: 1px solid #598FEF;
-  background-color: #EFEFEF;
-  padding: 2px;
-  z-index: 9999;
-}
-  div.colorPicker_hexWrap {width: 100%; float:left }
-  div.colorPicker_hexWrap label {font-size: 95%; color: #2F2F2F; margin: 5px 2px; width: 25%}
-  div.colorPicker_hexWrap input {margin: 5px 2px; padding: 0; font-size: 95%; border: 1px solid #000; width: 65%; }
-
-div.colorPicker-swatch {
-  height: 12px;
-  width: 12px;
-  border: 1px solid #000;
-  margin: 2px;
-  float: left;
-  cursor: pointer;
-  line-height: 12px;
-}
diff --git a/emperor/support_files/css/d3.parcoords.css b/emperor/support_files/css/d3.parcoords.css
deleted file mode 100644
index 7c443c6..0000000
--- a/emperor/support_files/css/d3.parcoords.css
+++ /dev/null
@@ -1,40 +0,0 @@
-.parcoords > svg, .parcoords > canvas { 
-  font: 14px sans-serif;
-  position: absolute;
-}
-.parcoords > canvas {
-  pointer-events: none;
-}
-.parcoords rect.background {
-  fill: transparent;
-}
-.parcoords rect.background:hover {
-  fill: rgba(120,120,120,0.2);
-}
-.parcoords .resize rect {
-  fill: rgba(0,0,0,0.1);
-}
-.parcoords rect.extent {
-  fill: rgba(255,255,255,0.25);
-  stroke: rgba(0,0,0,0.6);
-}
-.parcoords .axis line, .parcoords .axis path {
-  fill: none;
-  stroke: #fff;
-  shape-rendering: crispEdges;
-}
-
-.parcoords text {
-	stroke: #fff;
-	shape-rendering: crispEdges;
-}
-
-.parcoords canvas {
-  opacity: 1;
-  -moz-transition: opacity 0.3s;
-  -webkit-transition: opacity 0.3s;
-  -o-transition: opacity 0.3s;
-}
-.parcoords canvas.faded {
-  opacity: 0.25;
-}
diff --git a/emperor/support_files/css/emperor.css b/emperor/support_files/css/emperor.css
new file mode 100644
index 0000000..c778131
--- /dev/null
+++ b/emperor/support_files/css/emperor.css
@@ -0,0 +1,62 @@
+/* the plotting area */
+div.emperor-plot-wrapper {
+  height: 100%;
+  width: 73%;
+
+  font-size: 10px;
+
+  overflow: hidden;
+  float: left;
+  position: relative;
+  margin: 0;
+}
+
+/* #emperor-menu and #emperor-menu-tabs the two things that show in the right
+ * side-bar, #emperor-menu is the container for all the tabs and
+ * #emperor-menu-tabs is the container for the name of the tabs */
+div.emperor-plot-menu {
+  height: 100%;
+  width: 27%;
+
+  font-family: Helvetica, sans-serif;
+  font-size: 10px;
+
+  overflow: hidden;
+  float: left;
+  padding: 0px;
+  margin: 0;
+}
+
+/* class used in the divs that contain the widgets for the menu tabs like:
+ * axes, show by, and all the other tabs in the main interface.
+ */
+div.emperor-tab-div{
+  padding-top: 0px;
+  padding-bottom: 0px;
+  overflow: auto;
+  align: center; /*align the contents to the center*/
+}
+
+div.colorbox {
+  border: 1px solid black;
+  height: 18px;
+  width: 18px;
+}
+
+.ui-tabs .ui-tabs-nav li a{
+  padding: 2px 5px !important;
+}
+
+/*
+ * SlickGrid specific
+ *
+ * Gets rid of a horrible blue color that would otherwise get added to the
+ * grid, making it look not so slick. As suggested by:
+ *
+ * http://stackoverflow.com/a/17268879
+ **/
+.slick-row.ui-widget-content, .slick-cell {
+    background: none;
+}
+
+
diff --git a/emperor/support_files/css/images/ui-bg_flat_0_aaaaaa_40x100.png b/emperor/support_files/css/images/ui-bg_flat_0_aaaaaa_40x100.png
deleted file mode 100755
index 5b5dab2..0000000
Binary files a/emperor/support_files/css/images/ui-bg_flat_0_aaaaaa_40x100.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_flat_75_ffffff_40x100.png b/emperor/support_files/css/images/ui-bg_flat_75_ffffff_40x100.png
deleted file mode 100755
index ac8b229..0000000
Binary files a/emperor/support_files/css/images/ui-bg_flat_75_ffffff_40x100.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_glass_55_fbf9ee_1x400.png b/emperor/support_files/css/images/ui-bg_glass_55_fbf9ee_1x400.png
deleted file mode 100755
index ad3d634..0000000
Binary files a/emperor/support_files/css/images/ui-bg_glass_55_fbf9ee_1x400.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_glass_65_ffffff_1x400.png b/emperor/support_files/css/images/ui-bg_glass_65_ffffff_1x400.png
deleted file mode 100755
index 42ccba2..0000000
Binary files a/emperor/support_files/css/images/ui-bg_glass_65_ffffff_1x400.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_glass_75_dadada_1x400.png b/emperor/support_files/css/images/ui-bg_glass_75_dadada_1x400.png
deleted file mode 100755
index 5a46b47..0000000
Binary files a/emperor/support_files/css/images/ui-bg_glass_75_dadada_1x400.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_glass_75_e6e6e6_1x400.png b/emperor/support_files/css/images/ui-bg_glass_75_e6e6e6_1x400.png
deleted file mode 100755
index 86c2baa..0000000
Binary files a/emperor/support_files/css/images/ui-bg_glass_75_e6e6e6_1x400.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_glass_95_fef1ec_1x400.png b/emperor/support_files/css/images/ui-bg_glass_95_fef1ec_1x400.png
deleted file mode 100755
index 4443fdc..0000000
Binary files a/emperor/support_files/css/images/ui-bg_glass_95_fef1ec_1x400.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/emperor/support_files/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png
deleted file mode 100755
index 7c9fa6c..0000000
Binary files a/emperor/support_files/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-icons_222222_256x240.png b/emperor/support_files/css/images/ui-icons_222222_256x240.png
deleted file mode 100755
index b273ff1..0000000
Binary files a/emperor/support_files/css/images/ui-icons_222222_256x240.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-icons_2e83ff_256x240.png b/emperor/support_files/css/images/ui-icons_2e83ff_256x240.png
deleted file mode 100755
index 09d1cdc..0000000
Binary files a/emperor/support_files/css/images/ui-icons_2e83ff_256x240.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-icons_454545_256x240.png b/emperor/support_files/css/images/ui-icons_454545_256x240.png
deleted file mode 100755
index 59bd45b..0000000
Binary files a/emperor/support_files/css/images/ui-icons_454545_256x240.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-icons_888888_256x240.png b/emperor/support_files/css/images/ui-icons_888888_256x240.png
deleted file mode 100755
index 6d02426..0000000
Binary files a/emperor/support_files/css/images/ui-icons_888888_256x240.png and /dev/null differ
diff --git a/emperor/support_files/css/images/ui-icons_cd0a0a_256x240.png b/emperor/support_files/css/images/ui-icons_cd0a0a_256x240.png
deleted file mode 100755
index 2ab019b..0000000
Binary files a/emperor/support_files/css/images/ui-icons_cd0a0a_256x240.png and /dev/null differ
diff --git a/emperor/support_files/css/jquery-ui-1.8.16.custom.css b/emperor/support_files/css/jquery-ui-1.8.16.custom.css
deleted file mode 100755
index 9d83307..0000000
--- a/emperor/support_files/css/jquery-ui-1.8.16.custom.css
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-
-
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass. [...]
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
-.ui-widget-content a { color: #222222; }
-.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
-.ui-widget-header a { color: #222222; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
-
-/* Overlays */
-.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
-.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
- * jQuery UI Resizable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
- * jQuery UI Selectable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Accordion 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
-/*
- * jQuery UI Autocomplete 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }	
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.16
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
-	list-style:none;
-	padding: 2px;
-	margin: 0;
-	display:block;
-	float: left;
-}
-.ui-menu .ui-menu {
-	margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-	margin:0;
-	padding: 0;
-	zoom: 1;
-	float: left;
-	clear: left;
-	width: 100%;
-}
-.ui-menu .ui-menu-item a {
-	text-decoration:none;
-	display:block;
-	padding:.2em .4em;
-	line-height:1.5;
-	zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-	font-weight: normal;
-	margin: -1px;
-}
-/*
- * jQuery UI Button 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; } 
-button.ui-button-icons-only { width: 3.7em; } 
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4;  }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*
- * jQuery UI Dialog 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Slider 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: .5em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI Datepicker 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    display: none; /*sorry for IE5*/
-    display/**/: block; /*sorry for IE5*/
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}/*
- * jQuery UI Progressbar 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/emperor/support_files/css/jquery-ui2.css b/emperor/support_files/css/jquery-ui2.css
deleted file mode 100644
index 4ed1911..0000000
--- a/emperor/support_files/css/jquery-ui2.css
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-/*
- * jQuery UI Accordion 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
-/*
- * jQuery UI Autocomplete 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }	
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.16
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
-	list-style:none;
-	padding: 2px;
-	margin: 0;
-	display:block;
-	float: left;
-}
-.ui-menu .ui-menu {
-	margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-	margin:0;
-	padding: 0;
-	zoom: 1;
-	float: left;
-	clear: left;
-	width: 100%;
-}
-.ui-menu .ui-menu-item a {
-	text-decoration:none;
-	display:block;
-	padding:.2em .4em;
-	line-height:1.5;
-	zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-	font-weight: normal;
-	margin: -1px;
-}
-/*
- * jQuery UI Button 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; } 
-button.ui-button-icons-only { width: 3.7em; } 
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4;  }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*
- * jQuery UI Datepicker 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    display: none; /*sorry for IE5*/
-    display/**/: block; /*sorry for IE5*/
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}/*
- * jQuery UI Dialog 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Progressbar 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
- * jQuery UI Resizable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
- * jQuery UI Selectable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Slider 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; margin-top: 1em; margin-bottom: 1em; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
-
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; background: #6cf;}
-.ui-slider-horizontal .ui-slider-range-max { right: 0; background-position: 0 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
-.ui-widget-content { border: 1px solid #aaaaaa; background: #6cf;}
-.ui-widget-content a { color: #222222/*{fcContent}*/; }
-.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold;}
-.ui-widget-header a { color: #222222/*{fcHeader}*/; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
-.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
-.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
-.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
-.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
-.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
-
-/* Overlays */
-.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
-.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRad [...]
\ No newline at end of file
diff --git a/emperor/support_files/css/spectrum.css b/emperor/support_files/css/spectrum.css
deleted file mode 100755
index 20bc21d..0000000
--- a/emperor/support_files/css/spectrum.css
+++ /dev/null
@@ -1,408 +0,0 @@
-
-
-/***
-Spectrum: The No Hassle Colorpicker
-https://github.com/bgrins/spectrum
-
-Author: Brian Grinstead
-License: MIT
-***/
-
-.sp-container { 
-    position:absolute; 
-    top:0; 
-    left:0; 
-    display:inline-block;
-    *display: inline;
-    *zoom: 1;
-    z-index: 100;
-    overflow: hidden;
-}
-.sp-container.sp-flat {
-    position: relative;
-}
-
-/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */
-.sp-top {
-  position:relative; 
-  width: 100%;
-  display:inline-block;
-}
-.sp-top-inner {
-   position:absolute; 
-   top:0; 
-   left:0; 
-   bottom:0; 
-   right:0;
-}
-.sp-color { 
-    position: absolute;
-    top:0;
-    left:0;
-    bottom:0;
-    right:20%;
-}
-.sp-hue {
-    position: absolute;
-    top:0;
-    right:0;
-    bottom:0;
-    left:84%;
-    height: 100%;
-}
-.sp-fill { 
-    padding-top: 80%;
-}
-.sp-sat, .sp-val { 
-    position: absolute; 
-    top:0; 
-    left:0; 
-    right:0; 
-    bottom:0; 
-}
-
-/* Don't allow text selection */
-.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider , .sp-container.sp-dragging .sp-input, .sp-container button  { 
-    -webkit-user-select:none; 
-    -moz-user-select: none; 
-    -o-user-select:none; 
-    user-select: none; 
-}
-
-.sp-container.sp-input-disabled .sp-input-container {
-    display: none;
-}
-.sp-container.sp-buttons-disabled .sp-button-container {
-    display: none;
-}
-.sp-palette-only .sp-picker-container {
-    display: none;
-}
-.sp-palette-disabled .sp-palette-container {
-    display: none;
-}
-
-.sp-initial-disabled .sp-initial { 
-    display: none; 
-}
-
-
-/* Gradients for hue, saturation and value instead of images.  Not pretty... but it works */
-.sp-sat {
-    background-image: -webkit-gradient(linear,  0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0)));
-    background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
-    background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
-    background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
-    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)";
-    filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81');
-}
-.sp-val {
-    background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0)));
-    background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
-    background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
-    background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
-    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)";
-    filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000');
-}
-
-.sp-hue {
-    background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
-    background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
-    background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
-    background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000));
-    background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
-}
- 
-/* IE filters do not support multiple color stops.  
-   Generate 6 divs, line them up, and do two color gradients for each.
-   Yes, really.
- */
- 
-.sp-1 { 
-    height:17%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00');
-}
-.sp-2 { 
-    height:16%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00');
-}
-.sp-3 { 
-    height:17%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff');
-}
-.sp-4 { 
-    height:17%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff');
-}
-.sp-5 { 
-    height:16%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff');
-}
-.sp-6 { 
-    height:17%; 
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000');
-}
-
-/* Clearfix hack */
-.sp-cf:before, .sp-cf:after { content: ""; display: table; }
-.sp-cf:after { clear: both; }
-.sp-cf { *zoom: 1; }
-
-/* Mobile devices, make hue slider bigger so it is easier to slide */
- at media (max-device-width: 480px) {
-    .sp-color { right: 40%; }
-    .sp-hue { left: 63%; }
-    .sp-fill { padding-top: 60%; } 
-}
-
-.sp-dragger {
-   border-radius: 5px; 
-   height: 5px; 
-   width: 5px; 
-   border: 1px solid #fff;
-   background: #000;
-   cursor: pointer;
-   position:absolute; 
-   top:0; 
-   left: 0;
-}
-.sp-slider { 
-    position: absolute; 
-    top:0; 
-    cursor:pointer;
-    height: 3px; 
-    left: -1px;
-    right: -1px;
-    border: 1px solid #000;
-    background: white; 
-    opacity: .8; 
-}
-
-/* Basic display options (colors, fonts, global widths) */
-.sp-container {
-    border-radius: 0;
-    background-color: #ECECEC;
-    border: solid 1px #f0c49B;
-    padding: 0;
-}
-.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue 
-{
-    font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
-    -webkit-box-sizing: border-box;
-    -moz-box-sizing: border-box;
-    -ms-box-sizing: border-box;
-    box-sizing: border-box;
-}
-.sp-top 
-{
-    margin-bottom: 3px;
-}
-.sp-color, .sp-hue 
-{
-    border: solid 1px #666;
-}
-
-/* Input */
-.sp-input-container {
-    float:right;
-    width: 100px;
-    margin-bottom: 4px;
-}
-.sp-initial-disabled  .sp-input-container {
-    width: 100%;
-}
-.sp-input {
-   font-size: 12px !important;
-   border: 1px inset;
-   padding: 4px 5px;
-   margin: 0;
-   width: 100%;
-   background:transparent;
-   border-radius: 3px;
-   color: #222;
-}
-.sp-input:focus  {
-    border: 1px solid orange; 
-}
-.sp-input.sp-validation-error  
-{
-    border: 1px solid red;
-    background: #fdd;
-}
-.sp-picker-container , .sp-palette-container
-{
-    float:left;
-    position: relative;
-    padding: 10px;
-    padding-bottom: 300px;
-    margin-bottom: -290px;
-}
-.sp-picker-container 
-{
-    width: 172px;
-    border-left: solid 1px #fff;
-}
-
-/* Palettes */
-.sp-palette-container 
-{
-    border-right: solid 1px #ccc;
-}
-
-.sp-palette span {
-    display: block;
-    position:relative;
-    float:left;
-    width: 24px;
-    height: 15px; 
-    margin: 3px;
-    cursor: pointer;
-    border:solid 2px transparent;
-}
-.sp-palette span:hover, .sp-palette span.sp-thumb-active {
-    border-color: orange;
-}
-
-/* Initial */
-.sp-initial 
-{
-    float: left;
-    border: solid 1px #333;
-}
-.sp-initial span {
-    width: 30px;
-    height: 25px;
-    border:none;
-    display:block;
-    float:left;
-    margin:0;
-}
-
-/* Buttons */
-.sp-button-container {
-    float: right;
-}
-
-/* Replacer (the little preview div that shows up instead of the <input>) */
-.sp-replacer {
-    margin:0;
-    overflow:hidden;
-    cursor:pointer;
-    padding: 4px;
-    display:inline-block;
-    *zoom: 1;
-    *display: inline;
-    border: solid 1px #91765d;
-    background: #eee;
-    color: #333;
-    vertical-align: middle;
-}
-.sp-replacer:hover, .sp-replacer.sp-active {
-    border-color: #F0C49B;
-    color: #111;
-}
-.sp-dd { 
-    padding: 2px 0;
-    height: 16px; 
-    line-height: 16px;
-    float:left;
-    font-size:10px;
-}
-.sp-preview {
-    width:25px;
-    height: 20px;
-    border: solid 1px #222;
-    margin-right: 5px;
-    float:left;
-}
-
-.sp-palette  
-{
-    *width: 220px;
-    max-width: 220px;
-}
-.sp-palette span  
-{
-    width:16px; 
-    height: 16px; 
-    margin:2px 1px;
-    border: solid 1px #d0d0d0; 
-}
-
-.sp-container 
-{
-    padding-bottom:0;
-}
-
-
-/* Buttons: http://hellohappy.org/css3-buttons/ */
-.sp-container button {
-  background-color: #eeeeee;
-  background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
-  background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
-  background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
-  background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
-  background-image: linear-gradient(top, #eeeeee, #cccccc);
-  border: 1px solid #ccc;
-  border-bottom: 1px solid #bbb;
-  border-radius: 3px;
-  color: #333;
-  font-size: 14px;
-  line-height: 1;
-  padding: 5px 4px;
-  text-align: center;
-  text-shadow: 0 1px 0 #eee;
-  vertical-align: middle;
-}
-.sp-container button:hover {
-    background-color: #dddddd;
-    background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb);
-    background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb);
-    background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
-    background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
-    background-image: linear-gradient(top, #dddddd, #bbbbbb);
-    border: 1px solid #bbb;
-    border-bottom: 1px solid #999;
-    cursor: pointer;
-    text-shadow: 0 1px 0 #ddd; 
-}
-.sp-container button:active {
-    border: 1px solid #aaa;
-    border-bottom: 1px solid #888;
-    -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-    -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-    -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-    -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-    box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-}
-.sp-cancel
-{
-    font-size: 11px;
-    color: #d93f3f !important;
-    margin:0;
-    padding:2px;
-    margin-right: 5px;
-    vertical-align: middle;
-    text-decoration:none;
-    
-}
-.sp-cancel:hover 
-{
-    color: #d93f3f !important;
-    text-decoration: underline;
-} 
-
-
-.sp-palette span:hover, .sp-palette span.sp-thumb-active 
-{
-    border-color: #000;
-}
-.sp-palette span.sp-thumb-light.sp-thumb-active 
-{
-    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=);
-}
-
-.sp-palette span.sp-thumb-dark.sp-thumb-active 
-{
-    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkA [...]
-}
diff --git a/emperor/support_files/emperor/css/emperor.css b/emperor/support_files/emperor/css/emperor.css
deleted file mode 100644
index fff5837..0000000
--- a/emperor/support_files/emperor/css/emperor.css
+++ /dev/null
@@ -1,284 +0,0 @@
-    body, html {
-        font-size: 10px;
-        height: 100%;
-        width: 100%;
-        margin: 0px;
-        overflow: hidden;
-        float: left;
-    }
-    
-	#smalllogo {
-		width:150px;
-		height:45px;
-	}
-	
-    #overlay {
-    	visibility: hidden;
-    	position: absolute;
-    	left: 0px;
-    	top: 0px;
-    	width:100%;
-    	height:100%;
-    	font-size: 13px;
-    	text-align:center;
-    	z-index: 1000;
-	}
-    
-    #overlay div {
-    	width:325px;
-    	margin: 75px auto;
-    	background-color: #fff;
-    	border:1px solid #000;
-    	padding:15px;
-    	text-align:center;
-	}
-	
-	#explanation {
-		text-align:left;
-	}
-	
-	#source {
-		font-size:11px;
-		text-align:left;
-	}
-      
-    div.plotWrapper {
-        position: relative;
-        overflow:hidden;
-        height: 100%;
-        width:73%;
-        float: left;
-        margin:0;
-    }
-      
-    #plotToggle {
-        z-index: 5;
-        width: 73%;
-        margin:0;
-        overflow:hidden;
-        bottom: 0;
-        position: absolute;
-        float: left;
-    }
-
-    div.separator {
-        height:100%;
-        width:1%;
-        float:left;
-        cursor:col-resize;
-        margin:0;
-        background-color:#333333;
-    }
-    div.separator:hover {
-    	background-color:#666666;
-    }
-
-    div#menu {
-        height: 100%;
-        font-family: Helvetica, sans-serif;
-        width:26%;
-        overflow:hidden;
-        float:left;
-        padding: 0px;
-        margin:0;
-    }
-    
-    div#menutabs {
-        background: #eee;
-        /*margin-before: 0px !important;*/
-        height: 100%;
-        margin:0;
-    }
-    
-    .ui-tabs .ui-widget .ui-widget-content .ui-corner-all {
-        /*  height: 95%;*/
-        padding-left: 0px !important;
-        padding-top: 0px;
-    }
-    div#colorby {
-        padding-top: 0px;
-        padding-bottom: 0px;
-        width:100%;
-        height:100%;
-        overflow:scroll;
-    }
-    
-    div#keytab {
-        height: 94%;
-        width:90%;
-        padding-top: 0px;
-        padding-bottom: 0px;
-    }
-    
-    div#key {
-        height: 85%;
-        overflow: auto;
-    }
-    
-    table {
-        font-family: Helvetica, sans-serif;
-        font-size: 12px !important;
-    }
-    
-    select {
-        /*  height: 20%;*/
-        /*width: 100%;*/
-    }
-    
-    div.colorbox {
-        border: 1px solid black;
-        height: 18px;
-        width: 18px;
-    }
-    
-    div.animationlist {
-        margin-top: 1em;
-        width: 100%;
-        overflow: auto;
-        height: 60%;
-    }
-    
-    div.list{
-        width: 100%;
-        height: 85%;
-        overflow: auto;
-    }
-    
-    div.list ul {
-        width: 100%;
-        padding-left: 0px !important;
-        list-style-type: none;
-        font-size: 12px !important;
-    }
-    
-    input.button {
-        height: 2em;
-        width: 100%;
-    }
-    
-    label {
-        border:0; 
-        font: 9pt Helvetica;
-}
-    
-    label.slidervalue {
-        float: right;
-        border:0; 
-        color:#6cf; 
-        font-weight:bold;
-        font: 9pt Helvetica;
-    }
-
-    .ui-tabs .ui-tabs-nav li a{
-        padding: 2px 5px !important;
-    }
-    
-    div#labelby {
-        height: 90%;
-    }
-    
-    div#labellist {
-        height: 60%;
-    }
-    
-    div.labelsTop {
-        height: 30%;
-    }
-    
-    div#labels {
-        display: none;
-        font-family: courier;
-        color: #fff;
-        height: 0px;
-        float: left;
-        position: absolute;
-        z-index: 1;
-    }
-    
-    div#taxalabels {
-        display: none;
-        font-family: courier;
-        color: #fff;
-        height: 0px;
-        float: left;
-        position: absolute;
-        z-index: 1;
-    }
-    
-    .axislabels {
-        color: #fff;
-    }
-    
-    div#labelColorHolder {
-        width: 100%;
-    }
-    
-    div#labelColorHolder div {
-        float: left;
-    }
-    
-    div#labelColorHolder label{
-        float: left;
-        width: 50%;
-    }
-    
-    form {
-        margin: 0px;
-    }
-    
-    input {
-      font-style: 10pt helvetica;
-    }
-    
-    a.mediabutton img {
-        background-color: #eee;
-    }
-    
-    a.mediabutton:hover img{
-        background-color: #cff;
-    }
-    
-    *.unselectable {
-        -moz-user-select: -moz-none;
-        -khtml-user-select: none;
-        -webkit-user-select: none;
-
-        /*
-            Introduced in IE 10.
-            See http://ie.microsoft.com/testdrive/HTML5/msUserSelect/
-        */
-        -ms-user-select: none;
-        user-select: none;
-    }
-    
-    .ontop {
-        padding: 2px;
-        font-style: 9pt helvetica;
-        color: #fff;
-        border: 1px solid white;
-        position: absolute;
-    }
-    
-    .arrow-right {
-        opacity: 0;
-        position: absolute;
-        width: 0;
-        height: 0;
-        border-top: 5px solid transparent;
-        border-bottom: 5px solid transparent;
-        border-left: 10px solid white;
-    }
-    
-    .circle {
-        position: absolute;
-        opacity: 0;
-        border: 3px solid white;
-        border-radius: 50%;
-        width: 10px;
-        height: 10px; 
-        /* width and height can be anything, as long as they're equal */
-    }
-
-    .invisible {
-        display: none;
-    }
diff --git a/emperor/support_files/emperor/js/emperor.js b/emperor/support_files/emperor/js/emperor.js
deleted file mode 100644
index cf24422..0000000
--- a/emperor/support_files/emperor/js/emperor.js
+++ /dev/null
@@ -1,2430 +0,0 @@
-/*
- * __author__ = "Meg Pirrung"
- * __copyright__ = "Copyright 2013, Emperor"
- * __credits__ = ["Meg Pirrung","Antonio Gonzalez Pena","Yoshiki Vazquez Baeza",
- *                "Jackson Chen", "Emily TerAvest"]
- * __license__ = "BSD"
- * __version__ = "0.9.3"
- * __maintainer__ = "Meg Pirrung"
- * __email__ = "meganap at gmail.com"
- * __status__ = "Release"
- */
-
-// spheres and ellipses that are being displayed on screen
-var g_plotSpheres = {};
-var g_plotEllipses = {};
-var g_plotTaxa = {};
-var g_plotVectors = {};
-var g_plotEdges = {};
-var g_parallelPlots = []
-
-// sample identifiers of all items that are plotted
-var g_plotIds = [];
-
-// line objects used to represent the axes
-var g_xAxisLine;
-var g_yAxisLine;
-var g_zAxisLine;
-var g_viewingAxes = [0, 1, 2];
-
-// scene elements for the webgl plot
-var g_mainScene;
-var g_sceneCamera;
-var g_sceneLight;
-var g_mainRenderer;
-var g_sceneControl;
-
-// general multipurpose variables
-var g_elementsGroup; // group that holds the plotted shapes
-var g_categoryIndex = 0; // current coloring category index
-var g_genericSphere; // generic sphere used for plots
-var g_categoryName = ""; // current coloring category
-var g_foundId = ""; // id of currently located point
-var g_time;
-var g_visiblePoints = 0;
-var g_sphereScaler = 1.0;
-var g_keyBuilt = false;
-var g_useDiscreteColors = true;
-var g_screenshotBind;
-var g_separator_left;
-var g_separator_history;
-
-// valid ascii codes for filename
-var g_validAsciiCodes = new Array();
-// adding: .-_
-g_validAsciiCodes = g_validAsciiCodes.concat([45,46,95]);
-// adding: 0->9
-g_validAsciiCodes = g_validAsciiCodes.concat([48,49,50,51,52,53,54,55,56,57]);
-// adding: A->Z
-g_validAsciiCodes = g_validAsciiCodes.concat([65,66,67,68,68,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]);
-// adding: a->z
-g_validAsciiCodes = g_validAsciiCodes.concat([97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122]);
-
-// taken from the qiime/colors.py module; a total of 29 colors
-var k_QIIME_COLORS = [
-"0xFF0000", // red1
-"0x0000FF", // blue1
-"0xF27304", // orange1
-"0x008000", // green
-"0x91278D", // purple1
-"0xFFFF00", // yellow1
-"0x7CECF4", // cyan1
-"0xF49AC2", // pink1
-"0x5DA09E", // teal1
-"0x6B440B", // brown1
-"0x808080", // gray1
-"0xF79679", // red2
-"0x7DA9D8", // blue2
-"0xFCC688", // orange2
-"0x80C99B", // green2
-"0xA287BF", // purple2
-"0xFFF899", // yellow2
-"0xC49C6B", // brown2
-"0xC0C0C0", // gray2
-"0xED008A", // red3
-"0x00B6FF", // blue3
-"0xA54700", // orange3
-"0x808000", // green3
-"0x008080"] // teal3
-
-// Taken from http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
-function isNumeric(n) {
-  return !isNaN(parseFloat(n)) && isFinite(n);
-}
-
-/*This function recenter the camera to the initial position it had*/
-function resetCamera() {
-	// We need to reset the camera controls first before modifying the values of the camera (this is the reset view!)
-	g_sceneControl.reset();
-	
-	g_sceneCamera.aspect = document.getElementById('pcoaPlotWrapper').offsetWidth/document.getElementById('pcoaPlotWrapper').offsetHeight;
-	g_sceneCamera.rotation.set( 0, 0, 0);
-	g_sceneCamera.updateProjectionMatrix();
-	
-	if ($('#scale_checkbox').is(':checked'))
-		g_sceneCamera.position.set(0 , 0, (g_maximum*4.2) + g_radius);
-	else
-		g_sceneCamera.position.set(0 , 0, (g_maximum*4.8) + g_radius);	
-}
-
-/*Removes duplicates from a list of samples*/
-function dedupe(list) {
-	var set = {};
-	for (var i = 0; i < list.length; i++){
-		set[list[i]] = true;
-	}
-	list = [];
-	for (var obj in set){
-		list.push(obj);
-	}
-	return list;
-}
-
-/*Toggle between the scaled and unscaled version of the plot
-
-  This function will change multiple elements in the plot, as described by the
-  percentage explained in each of the PC axes.
-
-  Note that this function will also change the position of the camera, light and
-  adds a scaling value to the sphere size slider to make the size consistent
-  between scaled and unscaled versions of the plot.
-*/
-function toggleScaleCoordinates(element) {
-	var axesLen;
-	var operation;
-
-	// used only for vector and edges re-drawing
-	var currentPosition = [], currentColor = 0x000000;
-
-	if (!isNumeric(g_fractionExplained[g_viewingAxes[0]])) {
-		alert("PC" + (g_viewingAxes[0]+1) + " is too small for this feature, change your selection.");
-		return;
-	} else if (!isNumeric(g_fractionExplained[g_viewingAxes[1]])) {
-		alert("PC" + (g_viewingAxes[1]+1) + " is too small for this feature, change your selection.");
-		return;
-	} else if (!isNumeric(g_fractionExplained[g_viewingAxes[2]])) {
-		alert("PC" + (g_viewingAxes[2]+1) + " is too small for this feature, change your selection.");
-		return;
-	}
-
-	// XOR operation for the checkbox widget, this will select an operation
-	// to perform over various properties, either a multiplication or a division
-	if(element.checked == true){
-		operation = function(a, b){return a*b};
-		g_sphereScaler = g_fractionExplained[g_viewingAxes[0]];
-	}
-	else{
-		operation = function(a, b){return a/b};
-		g_sphereScaler = 1;
-	}
-
-	// force an update of the size of the spheres
-	$("#sradiusslider").slider("value",$("#sradiusslider").slider("value"));
-
-	// scale other properties
-	g_xMaximumValue = operation(g_xMaximumValue,g_fractionExplained[g_viewingAxes[0]]);
-	g_yMaximumValue = operation(g_yMaximumValue,g_fractionExplained[g_viewingAxes[1]]);
-	g_zMaximumValue = operation(g_zMaximumValue,g_fractionExplained[g_viewingAxes[2]]);
-	g_xMinimumValue = operation(g_xMinimumValue,g_fractionExplained[g_viewingAxes[0]]);
-	g_yMinimumValue = operation(g_yMinimumValue,g_fractionExplained[g_viewingAxes[1]]);
-	g_zMinimumValue = operation(g_zMinimumValue,g_fractionExplained[g_viewingAxes[2]]);
-	g_maximum = operation(g_maximum, g_fractionExplained[g_viewingAxes[0]])
-
-	// scale the position of the light
-	g_sceneLight.position.set(
-		operation(g_sceneLight.position.x, g_fractionExplained[g_viewingAxes[0]]),
-		operation(g_sceneLight.position.y, g_fractionExplained[g_viewingAxes[0]]),
-		operation(g_sceneLight.position.z, g_fractionExplained[g_viewingAxes[0]]));
-
-	// scale the position of the camera according to pc1
-	g_sceneCamera.position.set(
-		operation(g_sceneCamera.position.x, g_fractionExplained[g_viewingAxes[0]]),
-		operation(g_sceneCamera.position.y, g_fractionExplained[g_viewingAxes[0]]),
-		operation(g_sceneCamera.position.z, g_fractionExplained[g_viewingAxes[0]]))
-	// scale the axis lines
-	drawAxisLines();
-
-	// set the new position of each of the sphere objects
-	for (sample_id in g_plotSpheres){
-		// scale the position of the spheres
-		g_plotSpheres[sample_id].position.set(
-			operation(g_plotSpheres[sample_id].position.x,g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotSpheres[sample_id].position.y,g_fractionExplained[g_viewingAxes[1]]),
-			operation(g_plotSpheres[sample_id].position.z,g_fractionExplained[g_viewingAxes[2]]));
-	}
-
-	// ellipses won't always be available hence the two separate loops
-	for (sample_id in g_plotEllipses){
-		// scale the dimensions of the positions of each ellipse
-		g_plotEllipses[sample_id].position.set(
-			operation(g_plotEllipses[sample_id].position.x, g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotEllipses[sample_id].position.y, g_fractionExplained[g_viewingAxes[1]]),
-			operation(g_plotEllipses[sample_id].position.z, g_fractionExplained[g_viewingAxes[2]]));
-
-		// scale the dimensions of the ellipse
-		g_plotEllipses[sample_id].scale.set(
-			operation(g_plotEllipses[sample_id].scale.x, g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotEllipses[sample_id].scale.y, g_fractionExplained[g_viewingAxes[1]]),
-			operation(g_plotEllipses[sample_id].scale.z, g_fractionExplained[g_viewingAxes[2]]));
-	}
-
-	for (index in g_plotTaxa){
-		//scale the dimensions of the positions of each taxa-sphere
-		g_plotTaxa[index].position.set(
-			operation(g_plotTaxa[index].position.x, g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotTaxa[index].position.y, g_fractionExplained[g_viewingAxes[1]]),
-			operation(g_plotTaxa[index].position.z, g_fractionExplained[g_viewingAxes[2]]));
-
-		//scale the dimensions of each taxa-sphere
-		g_plotTaxa[index].scale.set(
-			operation(g_plotTaxa[index].scale.x, g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotTaxa[index].scale.y, g_fractionExplained[g_viewingAxes[0]]),
-			operation(g_plotTaxa[index].scale.z, g_fractionExplained[g_viewingAxes[0]]));
-	}
-
-	// each line is indexed by a sample, creating in turn TOTAL_SAMPLES-1 lines
-	for (sample_id in g_plotVectors){
-
-		// the color has to be formatted as an hex number for makeLine to work
-		currentColor = g_plotVectors[sample_id].material.color.getHex();
-
-		// updating the position of a vertex in a line is a really expensive
-		// operation, hence we just remove it from the group and create it again
-		g_elementsGroup.remove(g_plotVectors[sample_id]);
-
-		for (vertex in g_plotVectors[sample_id].geometry.vertices){
-			currentPosition[vertex] = g_plotVectors[sample_id].geometry.vertices[vertex];
-
-			// scale the position of each of the vertices
-			currentPosition[vertex].x = operation(currentPosition[vertex].x,
-				g_fractionExplained[g_viewingAxes[0]])
-			currentPosition[vertex].y = operation(currentPosition[vertex].y,
-				g_fractionExplained[g_viewingAxes[1]])
-			currentPosition[vertex].z = operation(currentPosition[vertex].z,
-				g_fractionExplained[g_viewingAxes[2]])
-
-			// create an array we can pass to makeLine
-			currentPosition[vertex] = [currentPosition[vertex].x,
-				currentPosition[vertex].y, currentPosition[vertex].z]
-		}
-
-		// add the element to the main vector array and to the group
-		g_plotVectors[sample_id] = makeLine(currentPosition[0],
-			currentPosition[1], currentColor, 2);
-		g_elementsGroup.add(g_plotVectors[sample_id]);
-	}
-
-	// support scaling of edges in plot comparisons
-	for(var sample_id in g_plotEdges){
-		// each edge is composed of two separate lines
-		for(var section in g_plotEdges[sample_id]){
-
-			// the color has to be formatted as an hex number for makeLine to work
-			currentColor = g_plotEdges[sample_id][section].material.color.getHex();
-
-			// remove them completely from the group and scene we no longer need
-			// these objects as re-creating them is as expensive as modifying
-			// most of their features
-			g_elementsGroup.remove(g_plotEdges[sample_id][section])
-			g_mainScene.remove(g_plotEdges[sample_id][section])
-
-			for (vertex in g_plotEdges[sample_id][section].geometry.vertices){
-				currentPosition[vertex] = g_plotEdges[sample_id][section].geometry.vertices[vertex];
-
-				// scale the position of each of the vertices
-				currentPosition[vertex].x = operation(currentPosition[vertex].x,
-					g_fractionExplained[g_viewingAxes[0]])
-				currentPosition[vertex].y = operation(currentPosition[vertex].y,
-					g_fractionExplained[g_viewingAxes[1]])
-				currentPosition[vertex].z = operation(currentPosition[vertex].z,
-					g_fractionExplained[g_viewingAxes[2]])
-
-				// create an array we can pass to makeLine
-				currentPosition[vertex] = [currentPosition[vertex].x,
-					currentPosition[vertex].y, currentPosition[vertex].z]
-			}
-
-			// add the element to the main vector array and to the group
-			g_plotEdges[sample_id][section] = makeLine(currentPosition[0],
-				currentPosition[1], currentColor, 2);
-			g_elementsGroup.add(g_plotEdges[sample_id][section]);
-			g_mainScene.add(g_plotEdges[sample_id][section]);
-
-		}
-	}
-}
-
-/* Toggle between discrete and continuous coloring for samples and labels */
-function toggleContinuousAndDiscreteColors(element){
-	g_useDiscreteColors = !element.checked;
-
-	// re-coloring the samples and labels now will use the appropriate coloring
-	colorByMenuChanged();
-	labelMenuChanged();
-}
-
-/*Generate a list of colors that corresponds to all the samples in the plot
-
-  This function will generate a list of coloring values depending on the
-  coloring scheme that the system is currently using (discrete or continuous).
-*/
-function getColorList(vals) {
-	var colors = {};
-
-	// cases with one or two categories are basically the same no matter if the
-	// coloring scheme is continuous or discrete; choose red or red and blue
-	if(vals.length == 1){
-		colors[vals[0]] = new THREE.Color();
-		colors[vals[0]].setHex("0xff0000");
-	}
-	else if (vals.length == 2) {
-		colors[vals[0]] = new THREE.Color();
-		colors[vals[0]].setHex("0xff0000");
-		colors[vals[1]] = new THREE.Color();
-		colors[vals[1]].setHex("0x0000ff");
-	}
-	else {
-		var numColors = vals.length;
-		for(var index in vals){
-			colors[vals[index]] = new THREE.Color();
-			if(g_useDiscreteColors){
-				// get the next available color
-				colors[vals[index]].setHex(getDiscreteColor(index)*1);
-			}
-			else{
-				//reverse the oder to standard default B->G->R
-				//changed what is multiplied by 0.66 to be 2,1,0 from 0,1,2
-				THREE.ColorConverter.setHSV(colors[vals[index]], 
-					   (numColors - index -1 )*.66/numColors, 1, 1);
-			}
-		}
-	}
-	return colors;
-}
-
-/* Retrieve one of the discrete colors from the list
-
-  This function will return the color at the requested index, if this value
-  value is greater than the number of colors available, the function will just
-  rollover and retrieve the next available color.
-*/
-function getDiscreteColor(index){
-	var size = k_QIIME_COLORS.length;
-	if(index >= size){
-		index = index - (Math.floor(index/size)*size)
-	}
-
-	return k_QIIME_COLORS[index]
-}
-
-/*Start timer (for debugging)*/
-function startTimer() {
-	var d=new Date()
-	g_time = d.getTime();
-}
-
-/*End timer (for debugging)*/
-function stopTimer(info) {
-	var d=new Date()
-	g_time = d.getTime() - g_time;
-	console.log("time to " +info +":"+g_time+"ms")
-}
-
-/* Sorting function that deals with alpha and numeric elements
-
-  This function takes a list of strings, divides it into two new lists, one
-  that's alpha-only and one that's numeric only. The resulting list will have
-  sorted all alpha elements at the beginning & all numeric elements at the end.
- */
-function _splitAndSortNumericAndAlpha(list){
-	var numericPart = [], alphaPart = [], result = [];
-
-	// separate the numeric and the alpha elements of the array
-	for(var index = 0; index < list.length; index++){
-		if(isNaN(parseFloat(list[index]))){
-			alphaPart.push(list[index])
-		}
-		else{
-			numericPart.push(list[index])
-		}
-	}
-
-	// sort each of the two parts, numeric part is ascending order
-	alphaPart.sort();
-	numericPart.sort(function(a,b){return parseFloat(a)-parseFloat(b)})
-
-	return result.concat(alphaPart, numericPart);
-}
-
-/*This function is called when a new value is selected in the colorBy menu */
-function colorByMenuChanged() {
-	// set the new current category and index
-	g_categoryName = document.getElementById('colorbycombo')[document.getElementById('colorbycombo').selectedIndex].value;
-	g_categoryIndex = g_mappingFileHeaders.indexOf(g_categoryName);
-
-	// get all values of this category from the mapping
-	var vals = [];
-	for(var i in g_plotIds){
-		vals.push(g_mappingFileData[g_plotIds[i]][g_categoryIndex]);
-	}
-
-	vals = _splitAndSortNumericAndAlpha(dedupe(vals));
-	colors = getColorList(vals);
-	
-	// build the colorby table in HTML
-	var lines = "<table id='colorbylist_table'>";
-	for(var i in vals){
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping file
-		// if this is done otherwise, weird characters have to be extemped etc.
-		var idString = "r"+i+"c"+g_categoryIndex;
-
-		// set the div id so that we can reference this div later
-		lines += "<tr><td><div id=\""+idString+"\"class=\"colorbox\" name=\""+vals[i]+"\"></div></td><td title=\""+vals[i]+"\">";
-
-		if(vals[i].length > 25){
-			lines+= vals[i].substring(0,25) + "..."
-		}
-		else{
-			lines += vals[i];
-		}
-
-		lines+= "</td></tr>";
-	}
-	lines += "</table>";
-	document.getElementById("colorbylist").innerHTML = lines;
-
-	for(var i in vals){
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping
-		var idString = "r"+i+"c"+g_categoryIndex;
-
-		// get the div built earlier and turn it into a color picker
-		$('#'+idString).css('backgroundColor',"#"+colors[vals[i]].getHexString());
-		$("#"+idString).spectrum({
-			localStorageKey: 'key',
-			color: colors[vals[i]].getHexString(),
-			showInitial: true,
-			showInput: true,
-			preferredFormat: "hex6",
-			change:
-				function(color) {
-					$(this).css('backgroundColor', color.toHexString());
-					var c = color.toHexString();
-					if(c.length == 4){
-						c = "#"+c.charAt(1)+c.charAt(1)+c.charAt(2)+c.charAt(2)+c.charAt(3)+c.charAt(3);
-					}
-					colorChanged($(this).attr('name'), c);
-					colors[$(this).attr('name')] = c;
-					colorParallelPlots(vals, colors);
-				}
-		});
-	}
-
-	colorParallelPlots(vals, colors);
-	setKey(vals, colors);
-}
-
-function colorParallelPlots(vals,colors) 
-{
-	pwidth = document.getElementById('parallelPlotWrapper').offsetWidth
-	pheight = document.getElementById('parallelPlotWrapper').offsetHeight
-	
-	document.getElementById('parallelPlotWrapper').innerHTML = '<div id="parallelPlot" class="parcoords" style="width:'+pwidth+'px;height:'+pheight+'px"></div>'
-	
-	var color = function(d) {
-		var colorKey = "";
-		for (var i = 1; i < Object.keys(d).length+1; i++) {
-			colorKey += String(d[i]);
-		}
-		var catValue = color_map[colorKey];
-		var catColor = colors[catValue];
-
-		try {
-			var hex = '#'+catColor.getHexString();
-		}catch(TypeError) {
-			var hex = catColor;
-		}
-		return hex;
-	}
-
-	var num_axes = g_fractionExplained.length-g_number_of_custom_axes;
-	var data2 = new Array();
-	var color_map = {};
-	for (sid in g_spherePositions) {
-		var a_map = {};
-		var key = "";
-		var value = g_mappingFileData[sid][g_categoryIndex];
-		for (var i = 1; i < num_axes+1; i++) {
-			a_map[i] = g_spherePositions[sid]['P'+i];
-			key += String(a_map[i]);
-		}
-		color_map[key] = value;
-		data2.push(a_map);
-	}
-
-	var pc = d3.parcoords()("#parallelPlot");
-	pc
-	  .data(data2)
-	  .color(color)
-	  .margin({ top: 40, left: 50, bottom: 40, right: 0 })
-	  .mode("queue")
-	  .render()
-	  .brushable();
-	  
-	$('.parcoords text').css('stroke', $('#axeslabelscolor').css('backgroundColor'));
-	$('.parcoords .axis line, .parcoords .axis path').css('stroke', $('#axescolor').css('backgroundColor'));
-}
-
-/*Callback when the scaling by drop-down menu changes
-
-  This function will create one slider and a label for each category.
-*/
-function scalingByMenuChanged(){
-	var scalingByCategoryName = document.getElementById('scalingbycombo')[document.getElementById('scalingbycombo').selectedIndex].value;
-	var scalingByCategoryIndex = g_mappingFileHeaders.indexOf(scalingByCategoryName);
-	var values = [], lines, idString;
-
-	// get all values of this category from the mapping
-	for(var i in g_plotIds){
-		values.push(g_mappingFileData[g_plotIds[i]][scalingByCategoryIndex]);
-	}
-	values = _splitAndSortNumericAndAlpha(dedupe(values));
-
-	// the padding accounts for the slider handle that can move all to the left or right
-	lines = '<table width="100%" height="100%" style="padding-right:10px;padding-left:10px;">'
-	for(var i in values){
-		// construct a sanitized category name for all HTML elements
-		idString = "r"+i+"c"+scalingByCategoryIndex;
-
-		lines += "<tr><td>";
-		// add a label with the name of the category
-		lines +=" <label for=\""+values[i]+"\" class=\"text\">"
-		// do not make the category name too long
-		if(values[i].length > 25){
-			lines+= values[i].substring(0,25) + "..."
-		}
-		else{
-			lines += values[i];
-		}
-		lines +="</label>"
-
-		// // add a slider and a current-value-label to the table
-		lines += "<label id=\""+idString+"scalingvalue\" name=\""+values[i]+"\" class=\"slidervalue\"></label>"
-		lines += "<div id=\""+idString+"scalingslider\" name=\""+values[i]+"\" class=\"slider-range-max\"></div>"
-		lines +="</td></tr>";
-	}
-	lines += "</table>";
-	document.getElementById("scalingbylist").innerHTML = lines;
-
-	// set all sliders to the default value of 5, that's reflected as no scaling
-	for(var i in values){
-		var idString = "r"+i+"c"+scalingByCategoryIndex;
-		$("#"+idString+"scalingslider").slider({
-			range: "max",
-			min: 1,
-			max: 20,
-			value: 5,
-			slide: function( event, ui ) {
-				sphereRadiusChange(ui, $(this).attr('name'));
-			},
-			change: function( event, ui ) {
-				sphereRadiusChange(ui, $(this).attr('name'));
-			}
-		});
-		document.getElementById(idString+"scalingvalue").innerHTML = $("#"+idString+"scalingslider").slider("value")/5;
-	}
-}
-
-
-/*This function is called when a new value is selected in the showBy menu*/
-function showByMenuChanged() {
-	g_categoryName = document.getElementById('showbycombo')[document.getElementById('showbycombo').selectedIndex].value;
-	var showByMenuIndex = g_mappingFileHeaders.indexOf(g_categoryName);
-	var vals = [];
-
-	for(var i in g_plotIds){
-		var sid = g_plotIds[i];
-		var divid = sid.replace(/\./g,'');
-		// get all of the values for the selected category
-		vals.push(g_mappingFileData[sid][showByMenuIndex]);
-		// set everything to visible
-		try {
-			g_elementsGroup.add(g_plotEllipses[sid])
-		}
-		catch(TypeError){}
-		try {
-			g_elementsGroup.add(g_plotSpheres[sid])
-		}
-		catch(TypeError){}
-		try {
-			g_elementsGroup.add(g_plotVectors[sid])
-		}
-		catch(TypeError){}
-		$('#'+divid+"_label").css('display','block');
-	}
-
-	g_visiblePoints = g_plotIds.length;
-	changePointCount();
-
-	vals = _splitAndSortNumericAndAlpha(dedupe(vals));
-
-	// build the showby checkbox table in HTML; the padding to the right makes
-	// the slider fit great inside the table without ever showing scroll bars
-	var lines = '<form name="showbyform"><table height="100%" width="100%" style="padding-right:10px;padding-left:10px;">'
-
-	for(var i in vals){
-		// tag each slider & percent label with the idString to avoid conflicts
-		var idString = "r"+i+"c"+showByMenuIndex;
-
-		// make the size of the checkmark fixed so proportions don't look weird
-		lines += "<tr><td width=\"10px\">";
-		lines +="<input name=\""+vals[i]+"_show\" value=\""+vals[i]+"\" type=\"checkbox\" checked=\"yes\" onClick=\"toggleVisible(\'"+vals[i]+"\')\">";
-		lines +="</input></td><td title=\""+vals[i]+"\">";
-		if(vals[i].length > 25){
-			lines+= vals[i].substring(0,25) + "..."
-		}
-		else{
-			lines += vals[i];
-		}
-
-		// add a slider and a current-value-label to the table
-		lines +="</td></tr>";
-		lines += '<td colspan="2">';
-		lines += "<label id=\""+idString+"opacityvalue\" name=\""+vals[i]+"\" class=\"slidervalue\"></label>"
-		lines += "<div id=\""+idString+"opacityslider\" name=\""+vals[i]+"\" class=\"slider-range-max\"></div>"
-		lines +="</td></tr>";
-	}
-	lines += "</table></form>";
-	document.getElementById("showbylist").innerHTML = lines;
-
-	// set all the sliders to 100 % and to respond to the sphereOpacityChange
-	// with the name of the category they have in the mapping file
-	for(var i in vals){
-		var idString = "r"+i+"c"+showByMenuIndex;
-		$("#"+idString+"opacityslider").slider({
-			range: "max",
-			min: 0,
-			max: 100,
-			value: 100,
-			slide: function( event, ui ) {
-				sphereOpacityChange(ui, $(this).attr('name'));
-			},
-			change: function( event, ui ) {
-				sphereOpacityChange(ui, $(this).attr('name'));
-			}
-		});
-		document.getElementById(idString+"opacityvalue").innerHTML = $("#"+idString+"opacityslider").slider("value")+"%";
-	}
-
-	// change the value of the general opacity for all the spheres, this action
-	// has to take place after the creation of the sliders for all categories;
-	// that is the for loop right befor this statement, as this will produce
-	// a callback that will require to change all the sliders in available
-	$("#sopacityslider").slider("value", 100)
-}
-
-/*Toggle plot items by category selected in showby menu*/
-function toggleVisible(value) {
-
-	var hidden = !document.showbyform.elements[value+'_show'].checked;
-	g_categoryName = document.getElementById('showbycombo')[document.getElementById('showbycombo').selectedIndex].value;
-
-	//change visibility of points depending on metadata category
-	for(var i in g_plotIds){
-	var sid = g_plotIds[i];
-	var divid = sid.replace(/\./g,'');
-	var mappingVal = g_mappingFileData[sid][g_mappingFileHeaders.indexOf(g_categoryName)]
-		if(mappingVal == value && hidden){
-			try{
-				g_elementsGroup.remove(g_plotEllipses[sid]);
-			}
-			catch(TypeError){}
-			try{
-				g_elementsGroup.remove(g_plotSpheres[sid]);
-				g_visiblePoints--
-			}
-			catch(TypeError){}
-			try{
-				g_elementsGroup.remove(g_plotVectors[sid]);
-			}
-			catch(TypeError){}
-			$('#'+divid+"_label").css('display','none');
-		}
-		else if(mappingVal == value && !hidden)
-		{
-			try {
-				g_elementsGroup.add(g_plotEllipses[sid]);
-			}
-			catch(TypeError){}
-			try {
-				g_elementsGroup.add(g_plotSpheres[sid]);
-				g_visiblePoints++;
-			}
-			catch(TypeError){}
-			try{
-				g_elementsGroup.add(g_plotVectors[sid]);
-			}
-			catch(TypeError){}
-			$('#'+divid+"_label").css('display','block');
-		}
-	}
-	changePointCount()
-
-}
-
-/*Build the plot legend in HTML*/
-function setKey(values, colors) {
-	if(g_keyBuilt){
-		for(var i = 0; i < values.length; i++){
-			colorChanged(values[i], '#'+colors[values[i]].getHexString());
-		}
-	}
-	else {
-		var keyHTML = "<table class=\"key\">";
-		for(var i in g_plotIds){
-			var sid = g_plotIds[i];
-			var divid = sid.replace(/\./g,'')+"_key";
-			var catValue = g_mappingFileData[sid][g_categoryIndex];
-			var catColor = colors[catValue];
-			keyHTML += "<tr id=\""+divid+"row\"><td><div id=\""+divid+"\" name=\""+sid+"\" class=\"colorbox\" style=\"background-color:#";
-			keyHTML += catColor.getHexString();
-			keyHTML += ";\"></div>";
-			keyHTML +="</td><td>";
-			keyHTML += sid;
-			keyHTML += "</td></tr>";
-
-			try {
-				g_plotEllipses[g_plotIds[i]].material.color.setHex("0x"+catColor.getHexString());
-			}
-			catch(TypeError){}
-			try {
-				g_plotSpheres[g_plotIds[i]].material.color.setHex("0x"+catColor.getHexString());
-			}
-			catch(TypeError){}
-			try {
-				g_plotVectors[g_plotIds[i]].material.color.setHex("0x"+catColor.getHexString());
-			}
-			catch(TypeError){}
-		}
-		keyHTML += "</table>";
-		document.getElementById("key").innerHTML = keyHTML;
-
-		for(var i in g_plotIds){
-			var sid = g_plotIds[i];
-			var divid = sid.replace(/\./g,'')+"_key";
-			$('#'+divid).attr('name',sid);
-			$('#'+divid).dblclick(function () {
-			toggleFinder($(this), $(this).attr('name'));
-			});
-		}
-		g_keyBuilt = true;
-	}
-}
-
-/*Toggle an arrow to locate a sample by double clicking the box @ the key menu*/
-function toggleFinder(div, divName) {
-	if(g_foundId != divName) {
-		$('.colorbox').css('border','1px solid black');
-		div.css('border','1px solid white');
-		$('#finder').css('opacity',1);
-		var coords = toScreenXY(g_plotSpheres[divName].position, g_sceneCamera, $('#main_plot'));
-		$('#finder').css('left',coords['x']-15);
-		$('#finder').css('top',coords['y']-5);
-		g_foundId = divName;
-	}
-	else {
-		if($('#finder').css('opacity') == 1) {
-			$('#finder').css('opacity',0);
-			div.css('border','1px solid black');
-			g_foundId = null
-		}
-		else {
-			$('#finder').css('opacity',1);
-			div.css('border','1px solid white');
-		}
-	}
-}
-
-/*Callback for the colorChanged event as triggered by the color picker*/
-function colorChanged(catValue,color) {
-	for(var i in g_plotIds)
-	{
-		var sid = g_plotIds[i]
-		if(g_mappingFileData[g_plotIds[i]][g_categoryIndex] == catValue)
-		{
-			// get the valid divId for the key and set its color
-			$("#"+sid.replace(/\./g,'')+"_key").css('backgroundColor',color);
-			// set the color of the corresponding sphere and ellipse 
-			try {
-				g_plotEllipses[sid].material.color.setHex(color.replace('#','0x'));
-			}
-			catch(TypeError){}
-			try {
-				g_plotSpheres[sid].material.color.setHex(color.replace('#','0x'));
-			}
-			catch(TypeError){}
-			try{
-				g_plotVectors[sid].material.color.setHex(color.replace('#','0x'));
-			}
-			catch(TypeError){}
-		}
-	}
-}
-
-/* This function is called when q new color is selected for #taxaspherescolor */
-function colorChangedForTaxaSpheres(color){
-	for (index in g_plotTaxa){
-		g_plotTaxa[index].material.color.setHex(color)
-	}
-}
-
-/* This function is called when a new color is selected for the edges
-
- The two input parameters are a hexadecimal formatted color and an index, the
- index indicates which side of the edges are going to be re-colored.
-*/
-function colorChangedForEdges(color, index){
-	for(var sample_id in g_plotEdges){
-		currentColor = g_plotEdges[sample_id][index].material.color.setHex(color);
-	}
-}
-
-/*This function is called when a new value is selected in the label menu*/
-function labelMenuChanged() {
-	if(document.getElementById('labelcombo').selectedIndex == 0){
-		document.getElementById("labellist").innerHTML = "";
-		return;
-	}
-
-	// set the new current category and index
-	var labelCategory = document.getElementById('labelcombo')[document.getElementById('labelcombo').selectedIndex].value;
-	var labelCatIndex = g_mappingFileHeaders.indexOf(labelCategory);
-
-	// get all values of this category from the mapping
-	var vals = [];
-	for(var i in g_plotIds){
-		vals.push(g_mappingFileData[g_plotIds[i]][labelCatIndex]);
-	}
-
-	vals = _splitAndSortNumericAndAlpha(dedupe(vals));
-	colors = getColorList(vals);
-
-	// build the label table in HTML
-	var lines = "<form name=\"labels\" id=\"labelForm\"><table>";
-	for(var i in vals){
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping file
-		// if this is done otherwise, weird characters have to be extemped etc.
-		var idString = "r"+i+"c"+g_categoryIndex;
-
-		// set the div id, checkbox name so that we can reference this later
-		lines += "<tr><td><input name=\""+vals[i]+"\" type=\"checkbox\" checked=\"true\" onClick=\"toggleLabels()\" ></input></td><td><div id=\""+idString+"Label\" class=\"colorbox\" name=\""+vals[i]+"\"></div></td><td title=\""+vals[i]+"\">";
-
-		if(vals[i].length > 25){
-			lines+= vals[i].substring(0,25) + "..."
-		}
-		else{
-			lines += vals[i];
-		}
-
-		lines+= "</td></tr>";
-	}
-
-	lines += "</table></form>";
-	document.getElementById("labellist").innerHTML = lines;
-
-	for(var i in vals){
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping file
-		// if this is done otherwise, weird characters have to be extemped etc.
-		var idString = "r"+i+"c"+g_categoryIndex;
-
-		// get the div built earlier and turn it into a color picker
-		$('#'+idString+'Label').css('backgroundColor',"#"+colors[vals[i]].getHexString());
-		labelColorChanged(vals[i], "#"+colors[vals[i]].getHexString());
-
-		$("#"+idString+'Label').spectrum({
-			color: colors[vals[i]].getHexString(),
-			showInitial: true,
-			showPalette: true,
-			preferredFormat: "hex6",
-			palette: [['red', 'green', 'blue']],
-			change:
-				function(color) {
-					$(this).css('backgroundColor', color.toHexString());
-					labelColorChanged($(this).attr('name'), color.toHexString());
-				}
-		});
-	}
-}
-
-/*This function is called when a label color is changed*/
-function labelColorChanged(value, color) {
-	g_categoryName = document.getElementById('labelcombo')[document.getElementById('labelcombo').selectedIndex].value;
-	value = value.replace('_','');
-
-	for(var i in g_plotIds){
-		var sid = g_plotIds[i];
-		var divid = sid.replace(/\./g,'');
-		if(g_mappingFileData[sid][g_mappingFileHeaders.indexOf(g_categoryName)] == value){
-			$('#'+divid+"_label").css('color', color);
-		}
-	}
-}
-
-/*This function turns the labels on and off*/
-function toggleLabels() {
-	if(document.plotoptions.elements[0].checked){
-		$('#labelForm').css('display','block');
-		$('#labels').css('display','block');
-		$("#lopacityslider").slider('enable');
-		$("#labelColor").spectrum('enable');
-		document.getElementById('labelcombo').disabled = false;
-
-		if(document.labels == null){
-			return;
-		}
-
-		// get the current category name to show the labels
-		g_categoryName = document.getElementById('labelcombo')[document.getElementById('labelcombo').selectedIndex].value;
-
-		// for each of the labels check if they are enabled or not
-		for(var i = 0; i < document.labels.elements.length; i++){
-			var hidden = !document.labels.elements[i].checked;
-			var value = document.labels.elements[i].name;
-
-			for(var j in g_plotIds){
-				var sid = g_plotIds[j];
-				var divid = sid.replace(/\./g,'');
-
-				if(g_mappingFileData[sid][g_mappingFileHeaders.indexOf(g_categoryName)] == value && hidden){
-					$('#'+divid+"_label").css('display', 'none');
-				}
-				else if(g_mappingFileData[sid][g_mappingFileHeaders.indexOf(g_categoryName)] == value && !hidden){
-					$('#'+divid+"_label").css('display', 'block');
-				}
-			}
-		}
-	}
-	else{
-		$('#labels').css('display','none');
-	}
-}
-
-/*This function turns the labels with the lineages on and off*/
-function toggleTaxaLabels(){
-	// present labels if the visibility checkbox is marked
-	if(document.biplotoptions.elements[0].checked){
-		$('#taxalabels').css('display','block');
-
-		for(var key in g_taxaPositions){
-			var taxa_label = g_taxaPositions[key]['lineage'];
-			var divid = taxa_label.replace(/\./g,'');
-			$('#'+key+"_taxalabel").css('display', 'block');
-		}
-	}
-	else{
-		$('#taxalabels').css('display','none');
-	}
-}
-
-/* Turn on and off the spheres representing the biplots on screen */
-function toggleBiplotVisibility(){
-	// reduce the opacity to zero if the element should be off or to 0.5
-	// if the element is supposed to be present; 0.5 is the default value
-	if(!document.biplotsvisibility.elements[0].checked){
-		for (index in g_plotTaxa){
-			g_mainScene.remove(g_plotTaxa[index]);
-		}
-	}
-	else{
-		for (index in g_plotTaxa){
-			g_mainScene.add(g_plotTaxa[index])
-		}
-	}
-}
-
-/* Turn on and off the lines connecting the samples being compared */
-function toggleEdgesVisibility(){
-
-	// each edge is really composed of two lines and those elements are stored
-	// in each of the keys that are stored for each sample comparison
-	if(!document.edgesvisibility.elements[0].checked){
-		for (index in g_plotEdges){
-			g_mainScene.remove(g_plotEdges[index][0]);
-			g_mainScene.remove(g_plotEdges[index][1]);
-		}
-	}
-	else{
-		for (index in g_plotEdges){
-			g_mainScene.add(g_plotEdges[index][0]);
-			g_mainScene.add(g_plotEdges[index][1]);
-		}
-	}
-}
-
-/*This function finds the screen coordinates of any position in the current plot.
-
-  The main purpose of this function is to be used for calculating the placement
-  of the labels.
-*/
-function toScreenXY( position, camera, jqdiv ) {
-
-	var screenPosition = position.clone();
-	var screenProjectionMatrix = new THREE.Matrix4();
-
-	// multiply the matrices and aply the vector to the projection matrix
-	screenProjectionMatrix.multiplyMatrices( camera.projectionMatrix,
-		camera.matrixWorldInverse);
-	screenPosition.applyProjection(screenProjectionMatrix);
-
-	return { x: (screenPosition.x + 1)*jqdiv.width()/2 + jqdiv.offset().left,
-		y: (-screenPosition.y+1)*jqdiv.height()/2 + jqdiv.offset().top};
-}
-
-/*This function is used to filter the key to a user's provided search string*/
-function filterKey() {
-	var searchVal = document.keyFilter.filterBox.value.toLowerCase();
-
-	for(var i in g_plotIds){
-		var sid = g_plotIds[i];
-		var divid = sid.replace(/\./g,'')+"_keyrow";
-
-		if(sid.toLowerCase().indexOf(searchVal) != -1){
-			$('#'+divid).css('display','block');
-		}
-		else{
-			$('#'+divid).css('display','none');
-		}
-	}
-}
-
-/*This function handles events from the ellipse opacity slider*/
-function ellipseOpacityChange(ui) {
-	document.getElementById('ellipseopacity').innerHTML = ui.value + "%";
-	ellipseOpacity = ui.value/100;
-
-	for(var sid in g_plotEllipses){
-		g_plotEllipses[sid].material.opacity = ellipseOpacity;
-	}
-}
-
-/*This function handles events from the sphere opacity sliders
-
-  Note that there are two type of sliders, the master opacity slider in the
-  options tab and the 'per-category' slider in the visibility tab. The later
-  one controls the opacity only for the spheres belonging to a specific category
-  in the mapping file.
-
-  As for the parameters 'ui' is the jQuery slider element and category the
-  string with the value of that category of the mapping file or null when the
-  callback is originated from the master opacity slider.
-*/
-function sphereOpacityChange(ui, category) {
-	var sphereOpacity = ui.value/100;
-	var showByCategoryName = document.getElementById('showbycombo')[document.getElementById('showbycombo').selectedIndex].value;
-	var showByCategoryIndex = g_mappingFileHeaders.indexOf(showByCategoryName);
-	var vals = [], idString, newValue;
-
-	// get all values of this category from the mapping
-	for(var i in g_plotIds){
-		vals.push(g_mappingFileData[g_plotIds[i]][showByCategoryIndex]);
-	}
-	vals = _splitAndSortNumericAndAlpha(dedupe(vals));
-
-	// category as null means that it's the general opacity slider (the on in the options tab)
-	if (category == null) {
-		for (index in vals){
-			idString = "r"+index+"c"+showByCategoryIndex;
-			$("#"+idString+"opacityslider").slider("value", ui.value);
-			document.getElementById(idString+"opacityvalue").innerHTML = $("#"+idString+"opacityslider").slider("value")+"%";
-		}
-		document.getElementById('sphereopacity').innerHTML = ui.value + "%";
-	}
-	else{
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping file
-		// if this is done otherwise, weird characters have to be extemped etc.
-		idString = "r"+vals.indexOf(category)+"c"+showByCategoryIndex;
-
-		for(var i in g_plotIds){
-			if(g_mappingFileData[g_plotIds[i]][showByCategoryIndex] == category){
-				g_plotSpheres[g_plotIds[i]].material.opacity = sphereOpacity;
-			}
-			document.getElementById(idString+"opacityvalue").innerHTML = $("#"+idString+"opacityslider").slider("value")+"%";
-		}
-	}
-}
-
-/*This function handles events from the vectors opacity slider*/
-function vectorsOpacityChange(ui) {
-	document.getElementById('vectorsopacity').innerHTML = ui.value + "%";
-	var vectorsOpacity = ui.value/100;
-
-	for(var sample_id in g_plotVectors){
-		g_plotVectors[sample_id].material.opacity = vectorsOpacity;
-	}
-}
-
-/*This function handles events from the label opacity slider*/
-function labelOpacityChange(ui) {
-	document.getElementById('labelopacity').innerHTML = ui.value + "%";
-	labelOpacity = ui.value/100;
-
-	$('#labels').css('opacity', labelOpacity);
-}
-
-/*This function handles events from the sphere radius slider
-
-  Note that this function will get a scaling value added depending on whether or
-  not the plot being displayed is scaled by the percent explained in each axis.
-
-  When the category argument is null, the callback comes from the master radius
-  slider in any other case it refers to a specific category.
-*/
-function sphereRadiusChange(ui, category) {
-	var scale = (ui.value/5.0)*g_sphereScaler;
-	var scalingByCategoryName = document.getElementById('scalingbycombo')[document.getElementById('scalingbycombo').selectedIndex].value;
-	var scalingByCategoryIndex = g_mappingFileHeaders.indexOf(scalingByCategoryName);
-	var values = [], idString;
-
-	// get all values of this category from the mapping
-	for(var i in g_plotIds){
-		values.push(g_mappingFileData[g_plotIds[i]][scalingByCategoryIndex]);
-	}
-	values = _splitAndSortNumericAndAlpha(dedupe(values));
-
-	if (category == null){
-		for (index in values){
-			idString = "r"+index+"c"+scalingByCategoryIndex;
-			$("#"+idString+"scalingslider").slider("value", ui.value);
-			document.getElementById(idString+"scalingvalue").innerHTML = $("#"+idString+"scalingslider").slider("value")/5;
-		}
-
-		// set the value for the master scaling slider
-		document.getElementById('sphereradius').innerHTML = ui.value/5;
-	}
-	else{
-		// each field is identified by the value it has in the deduplicated
-		// list of values and by the number of the column in the mapping file
-		// if this is done otherwise, weird characters have to be extemped etc.
-		idString = "r"+values.indexOf(category)+"c"+scalingByCategoryIndex;
-
-		for(var i in g_plotIds){
-			if(g_mappingFileData[g_plotIds[i]][scalingByCategoryIndex] == category){
-				g_plotSpheres[g_plotIds[i]].scale.set(scale, scale, scale);
-			}
-			document.getElementById(idString+"scalingvalue").innerHTML = $("#"+idString+"scalingslider").slider("value")/5;
-		}
-	}
-}
-
-/*Setup the interface elements required for the sidebar of the main interface*/
-function setJqueryUi() {
-	$("#menutabs").tabs();
-	$("#plottype").buttonset();
-	$("input[name='plottype']").change(togglePlots);
-	
-	$("#labelColor").css('backgroundColor', '#ffffff');
-
-	$("#labelColor").spectrum({
-		color: '#fffffff',
-		showInitial: true,
-		showPalette: true,
-		preferredFormat: "hex6",
-		palette: [['black', 'red', 'green', 'blue']],
-		change:
-			function(color) {
-				$(this).css('backgroundColor', color.toHexString());
-				$('#labels').css('color', color.toHexString());
-				for(var i in g_plotIds){
-					var sid = g_plotIds[i];
-					var divid = sid.replace(/\./g,'');
-					$('#'+divid+"_label").css('color', color.toHexString());
-				}
-				document.getElementById('labelcombo').selectedIndex = 0;
-				labelMenuChanged();
-			}
-	});
-
-	// check whether or not there is an ellipse opacity slider in the plot
-	if (document.getElementById('ellipseopacity')){
-		$("#eopacityslider").slider({
-			range: "max",
-			min: 0,
-			max: 100,
-			value: 20,
-			slide: function( event, ui ) {
-				ellipseOpacityChange(ui);
-			},
-			change: function( event, ui ) {
-				ellipseOpacityChange(ui);
-			}
-		});
-		document.getElementById('ellipseopacity').innerHTML = $( "#eopacityslider" ).slider( "value")+"%";
-	}
-
-	// check whether or not there is a vectors opacity slider in the plot
-	if (document.getElementById('vectorsopacity')){
-		$("#vopacityslider").slider({
-			range: "max",
-			min: 0,
-			max: 100,
-			value: 100,
-			slide: function( event, ui ) {
-				vectorsOpacityChange(ui);
-			},
-			change: function( event, ui ) {
-				vectorsOpacityChange(ui);
-			}
-		});
-		document.getElementById('vectorsopacity').innerHTML = $( "#vopacityslider" ).slider( "value")+"%";
-	}
-
-	// check if we are presenting biplots, to decide whether or not we should
-	// show the color picker for the biplot spheres, white is the default color
-	if(document.getElementById('taxaspherescolor')){
-		$('#taxaspherescolor').css('backgroundColor',"#FFFFFF");
-		$("#taxaspherescolor").spectrum({
-			localStorageKey: 'key',
-			color: "#FFFFFF",
-			preferredFormat: "hex6",
-			showInitial: true,
-			showInput: true,
-			change:
-				function(color) {
-					// pass a boolean flag to convert to hex6 string
-					var c = color.toHexString(true);
-					$(this).css('backgroundColor', c);
-					colorChangedForTaxaSpheres(c.replace('#', '0x'));
-				}
-		});
-	}
-	// set up the color selector for the taxa labels
-	if(document.getElementById('taxalabelcolor')){
-		$('#taxalabelcolor').css('backgroundColor',"#FFFFFF");
-		$("#taxalabelcolor").spectrum({
-			localStorageKey: 'key',
-			color: "#FFFFFF",
-			preferredFormat: "hex6",
-			showInitial: true,
-			showInput: true,
-			change:
-				function(color) {
-				// pass a boolean flag to convert to hex6 string
-				var c = color.toHexString(true);
-
-				// set the color for the box and for the renderer
-				$(this).css('backgroundColor', c);
-
-				// get the taxonomic assignments and append '_taxalabel' to
-				// retrieve all the labels belonging to a sphere in the plot
-				for(var key in g_taxaPositions) {
-					$('#'+key+"_taxalabel").css('color', c);
-				}
-			}// on-change callback
-		});
-	}
-
-	// check if the plot is a comparison plot if so, setup the elements that
-	// will allow the user to change the color of the two sides of the edges
-	if(document.getElementById('edgecolorselector_a')){
-		$('#edgecolorselector_a').css('backgroundColor',"#FFFFFF");
-		$("#edgecolorselector_a").spectrum({
-			localStorageKey: 'key',
-			color: "#FFFFFF",
-			preferredFormat: "hex6",
-			showInitial: true,
-			showInput: true,
-			change:
-				function(color) {
-					// pass a boolean flag to convert to hex6 string
-					var c = color.toHexString(true);
-					$(this).css('backgroundColor', c);
-					colorChangedForEdges(c.replace('#', '0x'), 0);
-				}
-		});
-	}
-	if(document.getElementById('edgecolorselector_b')){
-		$('#edgecolorselector_b').css('backgroundColor',"#FF0000");
-		$("#edgecolorselector_b").spectrum({
-			localStorageKey: 'key',
-			color: "#FF0000",
-			preferredFormat: "hex6",
-			showInitial: true,
-			showInput: true,
-			change:
-				function(color) {
-					// pass a boolean flag to convert to hex6 string
-					var c = color.toHexString(true);
-					$(this).css('backgroundColor', c);
-					colorChangedForEdges(c.replace('#', '0x'), 1);
-				}
-		});
-	}
-
-	$("#sopacityslider").slider({
-		range: "max",
-		min: 0,
-		max: 100,
-		value: 100,
-		slide: function( event, ui ) {
-			sphereOpacityChange(ui, null);
-		},
-		change: function( event, ui ) {
-			sphereOpacityChange(ui, null);
-		}
-	});
-	document.getElementById('sphereopacity').innerHTML = $( "#sopacityslider" ).slider( "value").toString()+"%";
-
-	$("#sradiusslider" ).slider({
-		range: "max",
-		min: 1,
-		max: 20,
-		value: 5,
-		slide: function( event, ui ) {
-			sphereRadiusChange(ui, null);
-		},
-		change: function( event, ui ) {
-			sphereRadiusChange(ui, null);
-		}
-	});
-	document.getElementById('sphereradius').innerHTML = $( "#sradiusslider" ).slider( "value")/5;
-
-	$("#lopacityslider").slider({
-		range: "max",
-		min: 0,
-		max: 100,
-		value: 100,
-		slide: function( event, ui ) {
-			labelOpacityChange(ui);
-		},
-		change: function( event, ui ) {
-			labelOpacityChange(ui);
-		}
-	});
-	document.getElementById('labelopacity').innerHTML = $( "#lopacityslider" ).slider( "value")+"%"
-
-	//default color for axes labels is white
-	$('#axeslabelscolor').css('backgroundColor',"#FFFFFF");
-	$("#axeslabelscolor").spectrum({
-		localStorageKey: 'key',
-		color: "#FFFFFF",
-		showInitial: true,
-		showInput: true,
-		showPalette: true,
-		preferredFormat: "hex6",
-		palette: [['white', 'black']],
-		change:
-			function(color) {
-				// pass a boolean flag to convert to hex6 string
-				var c = color.toHexString(true);
-				// set the color for the box and for the renderer
-				$(this).css('backgroundColor', c);
-
-				//set css for the text in the parallel plot
-				$('.parcoords text').css('stroke', c);
-
-				// change the css color of the 3d plot labels
-				$("#pc1_label").css('color', c);
-				$("#pc2_label").css('color', c);
-				$("#pc3_label").css('color', c);
-
-			}
-	});
-
-	//default color for the axes is white
-	$('#axescolor').css('backgroundColor',"#ffffff");
-	$("#axescolor").spectrum({
-		localStorageKey: 'key',
-		color: "#ffffff",
-		showInitial: true,
-		showInput: true,
-		showPalette: true,
-		preferredFormat: "hex6",
-		palette: [['white', 'black']],
-		change:
-			function(color) {
-				// pass a boolean flag to convert to hex6 string
-				var c = color.toHexString(true);
-				// create a new three.color from the string
-				var axesColor = new THREE.Color();
-				axesColor.setHex(c.replace('#','0x'));
-				g_xAxisLine.material.color = axesColor;
-				g_yAxisLine.material.color = axesColor;
-				g_zAxisLine.material.color = axesColor;
-
-
-				// set the color for the box and for the renderer
-				$(this).css('backgroundColor', c);
-
-				//set css for the lines of the parallel cords
-				$('.parcoords .axis line, .parcoords .axis path').css('stroke', c);
-			}
-	});
-
-	// the default color palette for the background is black and white
-	$('#rendererbackgroundcolor').css('backgroundColor',"#000000");
-	$('#parallelPlotWrapper').css('backgroundColor',"#000000");
-	$("#rendererbackgroundcolor").spectrum({
-		localStorageKey: 'key',
-		color: "#000000",
-		showInitial: true,
-		showInput: true,
-		showPalette: true,
-		preferredFormat: "hex6",
-		palette: [['white', 'black']],
-		change:
-			function(color) {
-				// pass a boolean flag to convert to hex6 string
-				var c = color.toHexString(true);
-
-				// create a new three.color from the string
-				var rendererBackgroundColor = new THREE.Color();
-				rendererBackgroundColor.setHex(c.replace('#','0x'));
-
-				// set the color for the box and for the renderer
-				$(this).css('backgroundColor', c);
-				g_mainRenderer.setClearColor(rendererBackgroundColor, 1);
-				
-				$('#parallelPlotWrapper').css('backgroundColor', c);
-			}
-	});
-}
-
-/*Draw the ellipses in the plot as described by the g_ellipsesDimensions array
-
-  Note that this is a function that won't always get executed since this should
-  only happen when plotting a jaccknifed principal coordinates analysis
-*/
-function drawEllipses() {
-	for(var sid in g_ellipsesDimensions) {
-		//draw ellipsoid
-		var emesh = new THREE.Mesh( g_genericSphere,new THREE.MeshLambertMaterial() );
-		emesh.scale.x = g_ellipsesDimensions[sid]['width']/g_radius;
-		emesh.scale.y = g_ellipsesDimensions[sid]['height']/g_radius;
-		emesh.scale.z = g_ellipsesDimensions[sid]['length']/g_radius;
-		emesh.position.set(g_ellipsesDimensions[sid]['x'],g_ellipsesDimensions[sid]['y'],g_ellipsesDimensions[sid]['z']);
-		emesh.material.color = new THREE.Color()
-		emesh.material.transparent = true;
-		emesh.material.depthWrite = false;
-		emesh.material.opacity = 0.2;
-		emesh.updateMatrix();
-		emesh.matrixAutoUpdate = true;
-		if(g_mappingFileData[sid] != undefined){
-			g_elementsGroup.add( emesh );
-			g_plotEllipses[sid] = emesh;
-		}
-	}
-}
-
-/*Draw the spheres in the plot as described by the g_spherePositions array*/
-function drawSpheres() {
-	for(var sid in g_spherePositions){
-		//draw ball
-		var mesh = new THREE.Mesh( g_genericSphere, new THREE.MeshLambertMaterial() );
-		mesh.material.color = new THREE.Color()
-		mesh.material.transparent = true;
-		mesh.material.depthWrite = false;
-		mesh.material.opacity = 1;
-		mesh.position.set(g_spherePositions[sid]['x'], g_spherePositions[sid]['y'], g_spherePositions[sid]['z']);
-		mesh.updateMatrix();
-		mesh.matrixAutoUpdate = true;
-		if(g_mappingFileData[sid] != undefined){
-			g_elementsGroup.add( mesh );
-			g_plotSpheres[sid] = mesh;
-			g_plotIds.push(sid);
-		}
-	}
-}
-
-/*Draw the taxa spheres in the plot as described by the g_taxaPositions array
-
-  Note that this is a function that won't always have an effect because the
-  g_taxaPositions array must have elements stored in it.
-*/
-function drawTaxa(){
-	// All taxa spheres are white by default
-	var whiteColor = new THREE.Color();
-	whiteColor.setHex("0xFFFFFF");
-
-	for (var key in g_taxaPositions){
-		var mesh = new THREE.Mesh(g_genericSphere,
-			new THREE.MeshLambertMaterial());
-
-		// set the volume of the sphere
-		mesh.scale.x = g_taxaPositions[key]['radius'];
-		mesh.scale.y = g_taxaPositions[key]['radius'];
-		mesh.scale.z = g_taxaPositions[key]['radius'];
-
-		// set the position
-		mesh.position.set(g_taxaPositions[key]['x'],
-			g_taxaPositions[key]['y'],
-			g_taxaPositions[key]['z']);
-
-		// the legacy color of these spheres is white
-		mesh.material.color = whiteColor;
-		mesh.material.transparent = true;
-		mesh.material.opacity = 0.5;
-		mesh.updateMatrix();
-		mesh.matrixAutoUpdate = true;
-
-		// add the element to the scene and to the g_plotTaxa dictionary
-		g_elementsGroup.add(mesh)
-		g_mainScene.add(mesh);
-		g_plotTaxa[key] = mesh;
-	}
-}
-
-/*Draw the lines for the plot as described in the g_vectorPositions array
-
-  Note that this will draw a single line between each of the samples, hence
-  resulting in N-1 lines being drawn where N is the total number of samples,
-  similarly to spheres or ellipsoids these elements are added to the
-  g_elementsGroup variable.
-*/
-function drawVectors(){
-	var current_vector, previous = null;
-
-	// There are as many vectors as categories were specified
-	for (var categoryKey in g_vectorPositions){
-		for (var sampleKey in g_vectorPositions[categoryKey]){
-
-			// retrieve the initial position on the first loop
-			if (previous == null){
-				previous = g_vectorPositions[categoryKey][sampleKey];
-			}
-			// if we already have the initial position, draw the line with
-			// the current position and the value of previous (initial position)
-			else{
-				current = g_vectorPositions[categoryKey][sampleKey];
-				current_vector = makeLine(previous, current, 0xFFFFFF, 2)
-				previous = current;
-				g_plotVectors[sampleKey] = current_vector;
-
-				if(g_mappingFileData[sampleKey] != undefined){
-					g_elementsGroup.add(current_vector);
-					g_plotVectors[sampleKey] = current_vector;
-				}
-			}
-		}
-
-		// reset previous so the algorithms work on the next category
-		previous = null;
-	}
-}
-
-/*Draw the lines that connect samples being compared (see g_comparePositiosn)
-
-  This will draw two lines between each compared sample, one with color red and
-  the other one with color white, what must be noted here is that, these two
-  lines visually compose a single line and are both stored in the g_plotEdges
-  array in arrays of two elements where the first element is the red line and
-  the second element is the white line.
-  
-  A dynamic value that contains the coordinates of the spheres is passed in, that way 
-  to allow the negating of the values.
-
-  In the case of a non-serial comparison plot, all edges will originate in the
-  same point.
-*/
-function drawEdges(spherepositions){
-	var previous = null, origin = null, current, middle_point, index=0, line_a, line_b;
-					
-	// note that this function is composed of an if-else statement with a loop
-	// that's almost identical under each case. This approach was taken as
-	// otherwise the comparison would need to happen N times instead of 1 time
-	// (N is the number of edges*2).
-
-	// if the comparison is serial draw one edge after the other
-	if (g_isSerialComparisonPlot == true){
-		for (var sampleKey in spherepositions){
-			for (var edgePosition in spherepositions[sampleKey]){
-			
-				// if we don't have a start point store it and move along
-				if (previous == null) {
-					previous = spherepositions[sampleKey][edgePosition];
-				}
-				// if we already have a start point then draw the edge
-				else{
-					current = spherepositions[sampleKey][edgePosition];
-					
-					// the edge is composed by two lines so calculate the middle
-					// point between these two lines and end the first line in this
-					// point and start the second line in this point
-					middle_point = [(previous[0]+current[0])/2,
-						(previous[1]+current[1])/2, (previous[2]+current[2])/2];
-
-					currentColorA_hex = $("#edgecolorselector_a").spectrum("get").toHexString(true);
-					currentColorB_hex = $("#edgecolorselector_b").spectrum("get").toHexString(true);
-					line_a = makeLine(previous, middle_point, currentColorA_hex, 2);
-					line_b = makeLine(middle_point, current, currentColorB_hex, 2);
-					line_a.transparent = false;
-					line_b.transparent = false;
-
-					// index the two lines by the name of the sample plus a suffix
-					g_plotEdges[sampleKey+'_'+index.toString()] = [line_a, line_b];
-
-					g_elementsGroup.add(line_a);
-					g_elementsGroup.add(line_b);
-					g_mainScene.add(line_a);
-					g_mainScene.add(line_b);
-
-					// the current line becomes the previous line for the next
-					// iteration as all samples must be connected
-					previous = spherepositions[sampleKey][edgePosition];
-				}
-				index = index+1;
-			}
-
-			// if we've finished with the connecting lines let a new line start
-			previous = null;
-		}
-	}
-	// if the comparison is not serial, originate all edges in the same coords
-	else{
-		for (var sampleKey in spherepositions){
-			for (var edgePosition in spherepositions[sampleKey]){
-				if (origin == null) {
-					origin = spherepositions[sampleKey][edgePosition];
-				}
-				else{
-					current = spherepositions[sampleKey][edgePosition];
-
-					// edges are composed of two lines so use the start and
-					// the end point to calculate the position of the vertices
-					middle_point = [(origin[0]+current[0])/2,
-						(origin[1]+current[1])/2, (origin[2]+current[2])/2];
-
-					// in the case of centered comparisons the origins are
-					// painted in color white one one side and red on the other
-					currentColorA_hex = $("#edgecolorselector_a").spectrum("get").toHexString(true);
-					currentColorB_hex = $("#edgecolorselector_b").spectrum("get").toHexString(true);
-					line_a = makeLine(origin, middle_point, currentColorA_hex, 2);
-					line_b = makeLine(middle_point, current, currentColorB_hex, 2);
-					line_a.transparent = false;
-					line_b.transparent = false;
-
-					// given that these are just sample repetitions just
-					// just add a suffix at the end of the sample id
-					g_plotEdges[sampleKey+'_'+index.toString()] = [line_a, line_b];
-
-					g_elementsGroup.add(line_a);
-					g_elementsGroup.add(line_b);
-					g_mainScene.add(line_a);
-					g_mainScene.add(line_b);
-
-				}
-				index = index + 1;
-			}
-			origin = null;
-		}
-	}
-}
-
-/*Save the current view to SVG
-  This will take the current webGL renderer, convert it to SVG and then generate 
-  a file to download. Additionally it will create the labels if this option is selected.
-*/
-function saveSVG(button){
-    // add a name subfix for the filenames
-    if ((g_segments<=8 && g_visiblePoints>=10000) || (g_segments>8 && g_visiblePoints>=5000)) {
-        var res = confirm("The number of segments (" + g_segments + ") combined with the number " +
-            "of samples could take a long time and in some computers the browser will crash. " +
-            "If this happens we suggest to lower the number of segments or use the png " +
-            "implementation. Do you want to continue?");
-        if (res==false) return;
-    }
- 
-    $('body').css('cursor','progress');
-    
-    var width = document.getElementById('pcoaPlotWrapper').offsetWidth;
-    var height = document.getElementById('pcoaPlotWrapper').offsetHeight;
-    
-    var color = $("#rendererbackgroundcolor").spectrum("get").toHexString(true);
-    var rendererBackgroundColor = new THREE.Color();
-    rendererBackgroundColor.setHex(color.replace('#','0x'));
-
-	var svgRenderer = new THREE.SVGRenderer({ antialias: true, preserveDrawingBuffer: true }); 
-	// this is the proper way to set the color of the background but it doesn't work   
-    svgRenderer.setClearColor(rendererBackgroundColor, 1);
-    svgRenderer.setSize(width, height);
-    svgRenderer.render(g_mainScene, g_sceneCamera);
-    svgRenderer.sortObjects = true;
-        
-    // converting svgRenderer to string: http://stackoverflow.com/questions/17398134/three-svgrenderer-save-text-of-image
-    var XMLS = new XMLSerializer(); 
-    var svgfile = XMLS.serializeToString(svgRenderer.domElement);
-    
-    // hacking the color to the svg
-    var index = svgfile.indexOf('viewBox="')+9;
-    var viewBox = svgfile.substring(index, svgfile.indexOf('"',index))
-    viewBox = viewBox.split(" ");
-    var background = '<rect id="background" height="' + viewBox[3] + '" width="' + viewBox[2] + '" y="' + 
-        viewBox[1] + '" x="' + viewBox[0] + '" stroke-width="0" stroke="#000000" fill="' + color + '"/>'
-    index = svgfile.indexOf('>',index)+1;
-    svgfile = svgfile.substr(0, index) + background + svgfile.substr(index);
-    
-    // adding xmlns header to open in the browser 
-    svgfile = svgfile.replace('viewBox=', 'xmlns="http://www.w3.org/2000/svg" viewBox=')
-    saveAs(new Blob([svgfile], {type: "text/plain;charset=utf-8"}), 
-         $('#saveas_name').val() + ".svg");
-    
-    if ($('#saveas_legends').is(':checked')) {
-        var labels_text = '', pos_y = 1, increment = 40, max_len = 0, font_size = 12;
-        $('#colorbylist_table tr div').each(function() {
-            if ($(this).attr('name').length > max_len) max_len = $(this).attr('name').length 
-            
-            // adding rectangle
-            labels_text += '<rect height="27" width="27" y="' + pos_y + 
-                '" x="1" stroke-width="1" ' + 'stroke="#FFFFFF" fill="' + 
-                $("#" + $(this).attr('id')).spectrum("get").toHexString(true) + '"/>';
-            // adding text
-            labels_text += '<text xml:space="preserve" y="' + (pos_y+20) + '" x="35" ' + 
-                'font-family="Monospace" font-size="' + font_size + '" stroke-width="0" ' +
-                'stroke="#000000" fill="#000000">' + $(this).attr('name') + '</text>';
-            pos_y += increment;
-        });
-        labels_text = '<svg width="' + ((font_size*max_len) + 10) + '" height="' + 
-            (pos_y-10) + '" xmlns="http://www.w3.org/2000/svg"><g>' + labels_text + 
-            '</g></svg>';
-        
-        saveAs(new Blob([labels_text], {type: "text/plain;charset=utf-8"}), 
-            $('#saveas_name').val() + "_labels.svg");
-    }
-    
-    $('body').css('cursor','default');
-}
-
-/*Utility function to draw two-vertices lines at a time
-
-  This function allows you to create a line with only two vertices i. e. the
-  start point and the end point, plus the color and width of the line. The
-  start and end point must be 3 elements array. The color must be a hex-string
-  or a hex number.
-*/
-function makeLine(coords_a, coords_b, color, width){
-	// based on the example described in:
-	// https://github.com/mrdoob/three.js/wiki/Drawing-lines
-	var material, geometry, line;
-
-	// make the material transparent and with full opacity
-	material = new THREE.LineBasicMaterial({color:color, linewidth:width});
-	material.matrixAutoUpdate = true;
-	material.transparent = true;
-	material.opacity = 1.0;
-
-	// add the two vertices to the geometry
-	geometry = new THREE.Geometry();
-	geometry.vertices.push(new THREE.Vector3(coords_a[0], coords_a[1], coords_a[2]));
-	geometry.vertices.push(new THREE.Vector3(coords_b[0], coords_b[1], coords_b[2]));
-
-	// the line will contain the two vertices and the described material
-	line = new THREE.Line(geometry, material);
-
-	return line;
-}
-
-/*Draw each of the lines that represent the X, Y and Z axes in the plot
-
-  The length of each of these axes depend on the ranges that the data being
-  displayed uses.
-*/
-function drawAxisLines() {
-	var axesColorFromColorPicker;
-
-	// removing axes, if they do not exist the scene doesn't complain
-	g_mainScene.remove(g_xAxisLine);
-	g_mainScene.remove(g_yAxisLine);
-	g_mainScene.remove(g_zAxisLine);
-
-	// value should be retrieved from the picker every time the axes are drawn
-	axesColorFromColorPicker = $("#axescolor").spectrum("get").toHexString(true);
-	axesColorFromColorPicker = axesColorFromColorPicker.replace('#','0x')
-	axesColorFromColorPicker = parseInt(axesColorFromColorPicker, 16)
-
-	// one line for each of the axes
-	g_xAxisLine = makeLine([g_xMinimumValue, g_yMinimumValue, g_zMinimumValue],
-		[g_xMaximumValue, g_yMinimumValue, g_zMinimumValue], axesColorFromColorPicker, 3);
-	g_yAxisLine = makeLine([g_xMinimumValue, g_yMinimumValue, g_zMinimumValue],
-		[g_xMinimumValue, g_yMaximumValue, g_zMinimumValue], axesColorFromColorPicker, 3);
-	g_zAxisLine = makeLine([g_xMinimumValue, g_yMinimumValue, g_zMinimumValue],
-		[g_xMinimumValue, g_yMinimumValue, g_zMaximumValue], axesColorFromColorPicker, 3);
-
-	// axes shouldn't be transparent
-	g_xAxisLine.material.transparent = false;
-	g_yAxisLine.material.transparent = false;
-	g_zAxisLine.material.transparent = false;
-
-	g_mainScene.add(g_xAxisLine)
-	g_mainScene.add(g_yAxisLine)
-	g_mainScene.add(g_zAxisLine)
-};
-
-/* update point count label */
-function changePointCount() {
-	document.getElementById('pointCount').innerHTML = g_visiblePoints+'/'+g_plotIds.length+' points'
-}
-
-/* Validating and modifying the view axes */
-function changeAxesDisplayed() {
-	if (!jQuery.isEmptyObject(g_vectorPositions) || !jQuery.isEmptyObject(g_taxaPositions) ||
-			!jQuery.isEmptyObject(g_ellipsesDimensions) || g_number_of_custom_axes!=0) {
-			resetCamera();
-			return;
-	}
-	
-	// HACK: this is a work around for cases when the scale is on
-	if ($('#scale_checkbox').is(':checked')) toggleScaleCoordinates({'checked': false});
-
-	var pc1_axis = $("#pc1_axis").val(), pc2_axis = $("#pc2_axis").val(),
-		pc3_axis = $("#pc3_axis").val();
-	var pc1_value = parseInt(pc1_axis.substring(1))-1,
-		pc2_value = parseInt(pc2_axis.substring(1))-1,
-		pc3_value = parseInt(pc3_axis.substring(1))-1;
-
-	//g_fractionExplained
-	if (pc1_axis==pc2_axis || pc1_axis==pc3_axis || pc2_axis==pc3_axis) {
-		$("#refresh_axes_label").html('<font color="red">Not valid values, try again.</font>');
-		return;
-	}
-	if (pc1_value>pc2_value || pc1_value>pc3_value || pc2_value>pc3_value) {
-		$("#refresh_axes_label").html('<font color="red">PC3 should be > than P2, and P2 than PC1.</font>');
-		return;
-	}
-
-	for (var sid in g_spherePositions) {
-		g_spherePositions[sid]['x'] = g_spherePositions[sid][pc1_axis];
-		g_spherePositions[sid]['y'] = g_spherePositions[sid][pc2_axis];
-		g_spherePositions[sid]['z'] = g_spherePositions[sid][pc3_axis];
-	}
-	
-	comparisonPositionlength = Object.keys(g_comparisonPositions).length
-	spherePositionslength = Object.keys(g_spherePositions).length/comparisonPositionlength
-	for (var sampleKey in g_comparisonPositions) {
-		for (var j=0;j<spherePositionslength;j++) {
-			var sid = sampleKey + "_" + j
-				g_comparisonPositions[sampleKey][j][0] = g_spherePositions[sid]['x']
-				g_comparisonPositions[sampleKey][j][1] = g_spherePositions[sid]['y']
-				g_comparisonPositions[sampleKey][j][2] = g_spherePositions[sid]['z']
- 		}
-	}
-	
-	checkedboxes = []
-    if ($('#flip_axes_1').is(':checked')) {
-		for(var sid in g_spherePositions){
-			g_spherePositions[sid]['x'] = g_spherePositions[sid][pc1_axis]*(-1);
-		}
- 		checkedboxes.push(0);
-	}
-    if ($('#flip_axes_2').is(':checked')) {
-		for(var sid in g_spherePositions){
-			g_spherePositions[sid]['y'] = g_spherePositions[sid][pc2_axis]*(-1);
-		}		
- 		checkedboxes.push(1);
-	}
-    if ($('#flip_axes_3').is(':checked')) {
-		for(var sid in g_spherePositions){
-			g_spherePositions[sid]['z'] = g_spherePositions[sid][pc3_axis]*(-1);
-		}		
- 		checkedboxes.push(2);
-	}
-	flipEdges(checkedboxes);
-	
-	// Setting up new positions
-	var max_x = Number.NEGATIVE_INFINITY, max_y = Number.NEGATIVE_INFINITY,
-		max_z = Number.NEGATIVE_INFINITY, min_x = Number.POSITIVE_INFINITY,
-		min_y = Number.POSITIVE_INFINITY, min_z = Number.POSITIVE_INFINITY;
-	for (var sid in g_spherePositions) {
-		if (g_spherePositions[sid]['x']>max_x)
-			max_x=g_spherePositions[sid]['x'];
-		if (g_spherePositions[sid]['y']>max_y)
-			max_y=g_spherePositions[sid]['y'];
-		if (g_spherePositions[sid]['z']>max_z)
-			max_z=g_spherePositions[sid]['z'];
-		if (g_spherePositions[sid]['x']<min_x)
-			min_x=g_spherePositions[sid]['x'];
-		if (g_spherePositions[sid]['y']<min_y)
-			min_y=g_spherePositions[sid]['y'];
-		if (g_spherePositions[sid]['z']<min_z)
-			min_z=g_spherePositions[sid]['z'];
-	}
-		
-	for (var sample_id in g_plotSpheres){
-		g_plotSpheres[sample_id].position.set(g_spherePositions[sample_id]['x'],
-			g_spherePositions[sample_id]['y'], g_spherePositions[sample_id]['z']);
-	}
-
-	// Setting up new axes for axes by coords explained
-	g_viewingAxes = [pc1_value, pc2_value, pc3_value]
-	g_pc1Label = "PC" + (g_viewingAxes[0]+1) + " (" + g_fractionExplainedRounded[g_viewingAxes[0]] + " %)";
-	g_pc2Label = "PC" + (g_viewingAxes[1]+1) + " (" + g_fractionExplainedRounded[g_viewingAxes[1]] + " %)";
-	g_pc3Label = "PC" + (g_viewingAxes[2]+1) + " (" + g_fractionExplainedRounded[g_viewingAxes[2]] + " %)";
-			
-	g_xMaximumValue = max_x + (max_x>=0 ? 6*g_radius : -6*g_radius);
-	g_yMaximumValue = max_y + (max_y>=0 ? 6*g_radius : -6*g_radius);
-	g_zMaximumValue = max_z + (max_z>=0 ? 6*g_radius : -6*g_radius);
-	g_xMinimumValue = min_x + (min_x>=0 ? 6*g_radius : -6*g_radius);
-	g_yMinimumValue = min_y + (min_y>=0 ? 6*g_radius : -6*g_radius);
-	g_zMinimumValue = min_z + (min_z>=0 ? 6*g_radius : -6*g_radius);
-	drawAxisLines();
-	buildAxisLabels();
-
-	// HACK: this is a work around for cases when the scale is on
-	if ($('#scale_checkbox').is(':checked')) toggleScaleCoordinates({'checked': true});
-	
-	// Change the css color of the 3d plot labels, set colors here because buildAxesLabels reverts color to default
-	axeslabelscolor = $('#axeslabelscolor').css( "background-color" );
-	axeslabelscolor_hex = $("#axeslabelscolor").spectrum("get").toHexString(true);
-	$("#pc1_label").css('color', axeslabelscolor);
-	$("#pc2_label").css('color', axeslabelscolor);
-	$("#pc3_label").css('color', axeslabelscolor);
-
-	resetCamera();
-}
-
-/*This function flips the lines in comparison plots when the user selects the option to negate the axes.*/
-function flipEdges(axis) {
-		var flippedPositions2d = new Array();
-		for (var sampleKey in g_comparisonPositions){
-			flippedPositions1d = []
-			for (var edgePosition in g_comparisonPositions[sampleKey]){
-				flippedPositions = [g_comparisonPositions[sampleKey][edgePosition][0], 
-									g_comparisonPositions[sampleKey][edgePosition][1],
-									g_comparisonPositions[sampleKey][edgePosition][2]]
-				for (var i=0;i<axis.length;i++) {
-					flippedPositions[axis[i]] *= (-1);
-				}
-				flippedPositions1d.push(flippedPositions);
-			}
-			flippedPositions2d[sampleKey] = flippedPositions1d;
-		}
-		removeEdges();
-		drawEdges(flippedPositions2d);
-}
-
-/*Removes the lines in comparison plots so the negated lines can be drawn*/
-function removeEdges() {
-	for(var sample_id in g_plotEdges){
-		for(var section in g_plotEdges[sample_id]){
-			g_mainScene.remove(g_plotEdges[sample_id][section]);
-		}
-	}
-}
-
-function clean_label_refresh_axes() {
-	$("#refresh_axes_label").html("");
-}
-
-function togglePlots() {
-
-	// set some interface changes for 3D visualizations
-	if(document.getElementById('pcoa').checked)
-	{
-		document.getElementById('pcoaPlotWrapper').className = 'plotWrapper';
-		document.getElementById('pcoaoptions').className = '';
-		document.getElementById('pcoaviewoptions').className = '';
-		document.getElementById('pcoaaxes').className = '';
-		document.getElementById('parallelPlotWrapper').className += ' invisible'
-		document.getElementById('paralleloptions').className += ' invisible'
-
-		// key menu is the default
-		$("#menutabs").tabs('select',0);
-
-		// make all tabs usable
-		$("#menutabs").tabs({disabled: []});
-		
-		// adding ctrl-p
-		g_screenshotBind = THREEx.Screenshot.bindKey(g_mainRenderer, {charCode: 16});
-	}
-	// changes for parallel plots
-	else{
-		document.getElementById('parallelPlotWrapper').className = document.getElementById('parallelPlotWrapper').className.replace(/(?:^|\s)invisible(?!\S)/ , '');
-		document.getElementById('paralleloptions').className = document.getElementById('paralleloptions').className.replace(/(?:^|\s)invisible(?!\S)/ , '');
-		document.getElementById('pcoaPlotWrapper').className += ' invisible'
-		document.getElementById('pcoaoptions').className += ' invisible'
-		document.getElementById('pcoaviewoptions').className += ' invisible'
-		document.getElementById('pcoaaxes').className += ' invisible'
-
-		// switch back to the key menu
-		$("#menutabs").tabs('select',0);
-
-		// make the visibility, scaling, labels and axes tabs un-usable
-		// they have no contextualized meaning in when lookin at parallel plots
-		// 0 = Key, 1 = Colors, 2 = Visibility, 3 = Scaling, 4 = Labels, 5 = Axes, 6 = View, 7 = Options
-		$("#menutabs").tabs({disabled: [2,3,4,5,7]});
-		
-		// removing the ctrl-p 
-        g_screenshotBind.unbind();
-		
-		colorByMenuChanged();
-	}
-}
-
-function setParallelPlots() {
-	g_parallelPlots = []
-
-	// get the number of axes being presented on screen but remove the ones
-	// that are represented by all of the custom axes (if there are any)
-	var num_axes = g_fractionExplained.length-g_number_of_custom_axes;
-
-	for(p in g_spherePositions){
-		var dataline = []
-		dataline.push(g_spherePositions[p].name)
-		for(var i = 1; i < num_axes+1; i++){
-			dataline.push(g_spherePositions[p]['P'+i])
-		}
-		g_parallelPlots.push(dataline)
-	}
-
-	pwidth = document.getElementById('pcoaPlotWrapper').offsetWidth
-	pheight = document.getElementById('pcoaPlotWrapper').offsetHeight
-
-	document.getElementById('parallelPlotWrapper').innerHTML = '<div id="parallelPlot" class="parcoords" style="width:'+pwidth+'px;height:'+pheight+'px"></div>'
-}
-
-// Resets the aspect ratio after dragging and window resize
-function aspectReset() {
-	winWidth = Math.min(document.getElementById('pcoaPlotWrapper').offsetWidth,document.getElementById('pcoaPlotWrapper').offsetHeight);
-	winAspect = document.getElementById('pcoaPlotWrapper').offsetWidth/document.getElementById('pcoaPlotWrapper').offsetHeight;                               
-	resetDivSizes(g_separator_left*$(window).width());
-	containmentLeft = $(window).width()*0.5;
-	containmentRight = $(window).width()*0.99;
-	g_sceneCamera.aspect = winAspect;
-	g_sceneCamera.updateProjectionMatrix();		
-
-}
-
-// Makes separator draggable and implements drag function
-function separator_draggable() {
-	$('.separator').draggable({
-		axis: 'x',
-		containment: [containmentLeft, 0, containmentRight, $(window).height()],
-		helper: 'clone',
-		drag: function (event, ui) {
-			offset = ui.offset.left;
-			if (offset > $(window).width()) {
-				offset = $(window).width()*0.99;
-			}
-			aspectReset();
-			resetDivSizes(offset);
-			if (offset < $(window).width()*0.93) {
-				g_separator_history = offset;
-			} 
-		}
-	});
-}
-         
-// Resizes plot and menu widths            
-function resetDivSizes(width_left) {
-	$('#plotToggle').width(width_left);
-	$('#parallelPlotWrapper').width(width_left);
-	$('#pcoaPlotWrapper').width(width_left);
-	if(document.getElementById('parallel').checked) {
-		togglePlots();
-	}
-	var width_right = $(window).width() - width_left - $('.separator').width()-1;                       
-	$('#menu').width(width_right);
-	g_separator_left = width_left/$(window).width();               
-	if (g_separator_left > 1) {
-		g_separator_left = 1;
-	}
-}
-
-/*Builds the axes labels from ground up after changing the axes*/
-function buildAxisLabels() {
-	//build axis labels
-	var axislabelhtml = "";
-	var xcoords = toScreenXY(new THREE.Vector3(g_xMaximumValue, g_yMinimumValue, g_zMinimumValue),g_sceneCamera,$('#main_plot'));
-	axislabelhtml += "<label id=\"pc1_label\" class=\"unselectable labels\" style=\"position:absolute; left:"+parseInt(xcoords['x'])+"px; top:"+parseInt(xcoords['y'])+"px;\">";
-	axislabelhtml += g_pc1Label;
-	axislabelhtml += "</label>";
-	var ycoords = toScreenXY(new THREE.Vector3(g_xMinimumValue, g_yMaximumValue, g_zMinimumValue),g_sceneCamera,$('#main_plot'));
-	axislabelhtml += "<label id=\"pc2_label\" class=\"unselectable labels\" style=\"position:absolute; left:"+parseInt(ycoords['x'])+"px; top:"+parseInt(ycoords['y'])+"px;\">";
-	axislabelhtml += g_pc2Label;
-	axislabelhtml += "</label>";
-	var zcoords = toScreenXY(new THREE.Vector3(g_xMinimumValue, g_yMinimumValue, g_zMaximumValue),g_sceneCamera,$('#main_plot'));
-	axislabelhtml += "<label id=\"pc3_label\" class=\"unselectable labels\" style=\"position:absolute; left:"+parseInt(zcoords['x'])+"px; top:"+parseInt(zcoords['y'])+"px;\">";
-	axislabelhtml += g_pc3Label;
-	axislabelhtml += "</label>";
-	document.getElementById("axislabels").innerHTML = axislabelhtml;
-}
-
-//Unhides the info box if WebGL is disabled
-function overlay() {
-	overlay = document.getElementById("overlay");
-	overlay.style.visibility = (overlay.style.visibility == "visible") ? "hidden" : "visible";
-	parallel = document.getElementById("menu");
-	parallel.style.visibility = (parallel.style.visibility == "invisible") ? "visible" : "hidden";
-	separator = document.getElementById("separator");
-	separator.style.visibility = (separator.style.visibility == "invisible") ? "visible" : "hidden";
-	plotToggle = document.getElementById("plotToggle");
-	plotToggle.style.visibility = (plotToggle.style.visibility == "invisible") ? "visible" : "hidden";
-}
-
-//Toggles fullscreen when double-clicking the separator
-function separatorDoubleClick() {
-	if (g_separator_left > 0.98) {
-		if (g_separator_history/$(window).width() < .5) {
-			g_separator_history = $(window).width()*.5;
-			resetDivSizes(g_separator_history);
-		}
-		else {
-			resetDivSizes(g_separator_history);
-		}
-	}
-	else {
-		resetDivSizes($(window).width()*0.99);
-	}
-	aspectReset();	
-}
-
-/*Setup and initialization function for the whole system
-
-  This function will set all of the WebGL elements that are required to exist
-  for the plot to work properly. This in turn will draw the ellipses, spheres
-  and all the other elements that could be part of a plot.
-*/
-$(document).ready(function() {
-	setJqueryUi()
-	
-	// Default sizes: g_separator_left is in percent and the others are in decimal
-	g_separator_left = 0.73;
-	g_separator_history = $(window).width()*0.73;
-	containmentLeft = $(window).width()*0.5;
-	containmentRight = $(window).width()*0.99;
-	// Detecting that webgl is activated
-	if ( ! Detector.webgl ) {
-		overlay();
-	}
-	var main_plot = $('#main_plot');
-	var particles, geometry, parameters, i, h, color;
-	var mouseX = 0, mouseY = 0;
-
-	var winWidth = Math.min(document.getElementById('pcoaPlotWrapper').offsetWidth,document.getElementById('pcoaPlotWrapper').offsetHeight), view_angle = 35, view_near = 0.0000001, view_far = 10000;
-	var winAspect = document.getElementById('pcoaPlotWrapper').offsetWidth/document.getElementById('pcoaPlotWrapper').offsetHeight;
-
-	$(window).resize(function() {	
-		aspectReset();
-		separator_draggable();
-	});
-	
-	separator_draggable();
-	
-	// Validating the string for the saveas filename = taken from http://stackoverflow.com/questions/6741175/trim-input-field-value-to-only-alphanumeric-characters-separate-spaces-with-wi
-    $('#saveas_name').keypress(function(event) {
-        var code = (event.keyCode ? event.keyCode : event.which);
-        if (g_validAsciiCodes.indexOf(code)==-1)
-            event.preventDefault();
-    });
-    
-    // Disables the enter key in the search bar
-    $('#searchBox').keypress(function(event) {
-    	if (event.keyCode == 13) {
-        	event.preventDefault();
-    	}
-	});
-
-	init();
-	animate();
-
-	function init() {
-		// assign a position to the camera befor associating it with other
-		// objects, else the original position will be lost and not make sense
-		g_sceneCamera = new THREE.PerspectiveCamera(view_angle, winAspect, view_near, view_far);
-		g_sceneCamera.position.set(0, 0, 0);
-
-		$('#main_plot canvas').attr('width',document.getElementById('pcoaPlotWrapper').offsetWidth);
-		$('#main_plot canvas').attr('height',document.getElementById('pcoaPlotWrapper').offsetHeight);
-
-		g_mainScene = new THREE.Scene();
-		g_mainScene.fog = new THREE.FogExp2( 0x000000, 0.0009);
-		g_mainScene.add(g_sceneCamera);
-
-		g_genericSphere = new THREE.SphereGeometry(g_radius, g_segments, g_rings);
-		g_elementsGroup = new THREE.Object3D();
-		g_mainScene.add(g_elementsGroup);
-
-		drawSpheres();
-		drawEllipses();
-		drawTaxa();
-		drawVectors();
-		drawEdges(g_comparisonPositions);
-
-		// set some of the scene properties
-		g_plotIds = g_plotIds.sort();
-		g_visiblePoints = g_plotIds.length;
-		changePointCount(g_visiblePoints)
-
-		// given that labels are turned off by default, leave a place holder
-		var line = "";
-		$("#labelcombo").append("<option>Select A Category...</option>");
-
-		// this sorted list of headers is only used in the following loop
-		// to create the 'color by', 'show by' and 'label by' drop-down menus
-		sortedMappingFileHeaders = _splitAndSortNumericAndAlpha(g_mappingFileHeaders)
-		for(var i in sortedMappingFileHeaders){
-			var temp = [];
-			for(var j in g_plotIds) {
-				if(g_mappingFileData[g_plotIds[j]] == undefined){
-					console.warning(g_plotIds[j] +" not in mapping")
-					continue
-				}
-				temp.push(g_mappingFileData[g_plotIds[j]][i])
-			}
-			temp = dedupe(temp);
-			
-			// note that each category is added to all the dropdown menus in the
-			// user interface, these are declared in _EMPEROR_FOOTER_HTML_STRING
-			if (i==0) {
-			    line = "<option selected value=\""+sortedMappingFileHeaders[i]+"\">"+sortedMappingFileHeaders[i]+"</option>"
-			} else {
-			    line = "<option value=\""+sortedMappingFileHeaders[i]+"\">"+sortedMappingFileHeaders[i]+"</option>"
-			}
-			$("#colorbycombo").append(line);
-			$("#scalingbycombo").append(line);
-			$("#showbycombo").append(line);
-			$("#labelcombo").append(line);
-		}
-
-		setParallelPlots();
-
-		colorByMenuChanged();
-		showByMenuChanged();
-		scalingByMenuChanged();
-
-		togglePlots();
-
-		// the light is attached to the camera to provide a 3d perspective
-		g_sceneLight = new THREE.DirectionalLight(0x999999, 2);
-		g_sceneLight.position.set(1,1,1).normalize();
-		g_sceneCamera.add(g_sceneLight);
-
-		// Adding camera
-		g_sceneControl = new THREE.TrackballControls(g_sceneCamera, document.getElementById('main_plot'));
-		g_sceneControl.rotateSpeed = 1.0;
-		g_sceneControl.zoomSpeed = 1.2;
-		g_sceneControl.panSpeed = 0.8;
-		g_sceneControl.noZoom = false;
-		g_sceneControl.noPan = false;
-		g_sceneControl.staticMoving = true;
-		g_sceneControl.dynamicDampingFactor = 0.3;
-		g_sceneControl.keys = [ 65, 83, 68 ];
-
-		// black is the default background color for the scene
-		var rendererBackgroundColor = new THREE.Color();
-		rendererBackgroundColor.setHex("0x000000");
-
-		// renderer, the default background color is black
-		g_mainRenderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
-        
-        // adding 'ctrl+p' to print screenshot
-        g_screenshotBind = THREEx.Screenshot.bindKey(g_mainRenderer, {charCode: 16});
-        
-		g_mainRenderer.setClearColor(rendererBackgroundColor, 1);
-		g_mainRenderer.setSize( document.getElementById('pcoaPlotWrapper').offsetWidth, document.getElementById('pcoaPlotWrapper').offsetHeight );
-		g_mainRenderer.sortObjects = true;
-		main_plot.append(g_mainRenderer.domElement);
-
-		// build divs to hold point labels and position them
-		var labelshtml = "";
-		for(var i in g_plotIds) {
-			var sid = g_plotIds[i];
-			var divid = sid.replace(/\./g,'');
-			mesh = g_plotSpheres[sid];
-			var coords = toScreenXY(mesh.position,g_sceneCamera,$('#main_plot'));
-			labelshtml += "<label id=\""+divid+"_label\" class=\"unselectable labels\" style=\"position:absolute; left:"+parseInt(coords['x'])+"px; top:"+parseInt(coords['y'])+"px;\">";
-			labelshtml += sid;
-			labelshtml += "</label>";
-		}
-		document.getElementById("labels").innerHTML = labelshtml;
-
-		labelshtml = "";
-		// add the labels with the taxonomic lineages to the taxalabels div
-		for(var key in g_taxaPositions){
-
-			// get the coordinate of this taxa sphere
-			var coords = toScreenXY(g_plotTaxa[key].position,g_sceneCamera,$('#main_plot'));
-
-			// labels are identified by the key they have in g_taxaPositions
-			labelshtml += "<label id=\""+key+"_taxalabel\" class=\"unselectable labels\" style=\"position:absolute; left:"+parseInt(coords['x'])+"px; top:"+parseInt(coords['y'])+"px;\">";
-			labelshtml += g_taxaPositions[key]['lineage'];
-			labelshtml += "</label>";
-		}
-		document.getElementById("taxalabels").innerHTML = labelshtml
-		
-		// adding values for axes to display
-		drawMenuAxesDisplayed();
-		changeAxesDisplayed();
-		drawAxisLines();
-
-		buildAxisLabels();
-	}
-
-	function drawMenuAxesDisplayed() {
-		if (!jQuery.isEmptyObject(g_vectorPositions) || !jQuery.isEmptyObject(g_taxaPositions) ||
-			!jQuery.isEmptyObject(g_ellipsesDimensions) || g_number_of_custom_axes!=0) {
-			text = '<table width="100%%">';
-			text += '<tr><td><font color="red">This is disabled for custom axes, biplots, vectors, and jackknifed</font></td></tr>';
-			text += '</table>';
-			document.getElementById("axeslist").innerHTML = text;
-			return;
-		}
-
-		text = '<table border="0" width="80%">';
-
-		// Adding 1st axis
-		text += '<tr>'
-		text += '<td width="40px" class="unselectable lables">Axis 1:</td>'
-		text += '<td><select id="pc1_axis" onchange="clean_label_refresh_axes();">';
-
-		for (var i=1; i < g_fractionExplainedRounded.length + 1; i++) {
-			if (i==1) {
-				text += '<option selected value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			} else {
-				text += '<option value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			}
-		}
-		text += '</select></td>'
-		text += '<td>Negate values:<input id="flip_axes_1" class="checkbox" type="checkbox" style=""></td>';
-		text += '</tr>';
-
-		// Adding 2nd axis
-		text += '<tr>'
-		text += '<td width="40px" class="unselectable lables">Axis 2:</td>'
-		text += '<td><select id="pc2_axis" onchange="clean_label_refresh_axes();">';
-		for (var i=1; i < g_fractionExplained.length + 1; i++) {
-			if (i==2) {
-				text += '<option selected value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			} else {
-				text += '<option value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			}
-		}
-		text += '</select></td>'
-		text += '<td>Negate values:<input id="flip_axes_2" class="checkbox" type="checkbox" style=""></td>';
-		text += '</tr>';
-
-		// Adding 3rd axis
-		text += '<tr>'
-		text += '<td width="40px" class="unselectable lables">Axis 3:</td>'
-		text += '<td><select id="pc3_axis" onchange="clean_label_refresh_axes();">';
-		for (var i=1; i < g_fractionExplained.length + 1; i++) {
-			if (i==3) {
-				text += '<option selected value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			} else {
-				text += '<option value="P' + i + '">P' + i + " (" + g_fractionExplainedRounded[i-1] + "%)" + '</option>';
-			}
-		}
-		text += '</select></td>'
-		text += '<td>Negate values:<input id="flip_axes_3" class="checkbox" type="checkbox" style=""></td>';
-		text += '</tr>';
-		text += '</table>';
-
-		// Adding button
-		text += '<table width="100%%"><tr>';
-		text += '<td width="20px"><input type="button" value="Refresh" onclick="changeAxesDisplayed();"></td>';
-		text += '<td id="refresh_axes_label"></td></tr>';
-		text += '</table>';
-		document.getElementById("axeslist").innerHTML = text;
-	}
-
-	function animate() {
-		requestAnimationFrame( animate );
-
-		render();
-
-		var labelCoordinates;
-
-		// reposition the labels for the axes in the 3D plot
-		labelCoordinates = toScreenXY(new THREE.Vector3(g_xMaximumValue, g_yMinimumValue, g_zMinimumValue), g_sceneCamera,$('#main_plot'));
-		$("#pc1_label").css('left', labelCoordinates['x'])
-		$("#pc1_label").css('top', labelCoordinates['y'])
-		labelCoordinates = toScreenXY(new THREE.Vector3(g_xMinimumValue, g_yMaximumValue, g_zMinimumValue), g_sceneCamera,$('#main_plot'));
-		$("#pc2_label").css('left', labelCoordinates['x'])
-		$("#pc2_label").css('top', labelCoordinates['y'])
-		labelCoordinates = toScreenXY(new THREE.Vector3(g_xMinimumValue, g_yMinimumValue, g_zMaximumValue), g_sceneCamera,$('#main_plot'));
-		$("#pc3_label").css('left', labelCoordinates['x'])
-		$("#pc3_label").css('top', labelCoordinates['y'])
-
-
-		// move labels when the plot is moved
-		if(document.plotoptions.elements[0].checked){
-			for(var i in g_plotIds) {
-				var sid = g_plotIds[i];
-				mesh = g_plotSpheres[sid];
-				var coords = toScreenXY(mesh.position, g_sceneCamera, $('#main_plot'));
-				var divid = sid.replace(/\./g,'');
-				$('#'+divid+"_label").css('left',coords['x']);
-				$('#'+divid+"_label").css('top',coords['y']);
-			}
-		}
-		// check if you have to reposition the taxa labels for each frame
-		// this is something that will only happen when drawing biplots
-		if(document.biplotoptions){
-			if(document.biplotoptions.elements[0].checked){
-				for(var key in g_taxaPositions) {
-					// retrieve the position of the taxa on screen
-					var coords = toScreenXY(g_plotTaxa[key].position,
-						g_sceneCamera, $('#main_plot'));
-
-					// add the label at the appropriate position
-					$('#'+key+"_taxalabel").css('left',coords['x']);
-					$('#'+key+"_taxalabel").css('top',coords['y']);
-				}
-			}
-		}
-		if(g_foundId) {
-			var coords = toScreenXY(g_plotSpheres[g_foundId].position, g_sceneCamera, $('#main_plot'));
-			$('#finder').css('left',coords['x']-15);
-			$('#finder').css('top',coords['y']-5);
-		}
-	}
-   
-	function render() {
-		g_sceneControl.update();
-		g_mainRenderer.setSize( document.getElementById('pcoaPlotWrapper').offsetWidth, document.getElementById('pcoaPlotWrapper').offsetHeight );
-		g_mainRenderer.render( g_mainScene, g_sceneCamera);
-	}
-	
-});
diff --git a/emperor/support_files/js/FileSaver.min.js b/emperor/support_files/js/FileSaver.min.js
deleted file mode 100755
index f69f857..0000000
--- a/emperor/support_files/js/FileSaver.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
-var saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){"use strict";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS("http://www.w3.org/1999/xhtml","a"),s="download"in i,o=function(n){var r=t.createEvent("MouseEvents");r.initMouseEvent("click",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=fun [...]
diff --git a/emperor/support_files/js/THREEx.screenshot.js b/emperor/support_files/js/THREEx.screenshot.js
deleted file mode 100644
index 180f531..0000000
--- a/emperor/support_files/js/THREEx.screenshot.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/** @namespace */
-var THREEx	= THREEx 		|| {};
-
-// TODO http://29a.ch/2011/9/11/uploading-from-html5-canvas-to-imgur-data-uri
-// able to upload your screenshot without running servers
-
-// forced closure
-(function(){
-
-	/**
-	 * Take a screenshot of a renderer
-	 * - require WebGLRenderer to have "preserveDrawingBuffer: true" to be set
-	 * - TODO is it possible to check if this variable is set ? if so check it
-	 *   and make advice in the console.log
-	 *   - maybe with direct access to the gl context...
-	 * 
-	 * @param {Object} renderer to use
-	 * @param {String} mimetype of the output image. default to "image/png"
-	 * @param {String} dataUrl of the image
-	*/
-	var toDataURL	= function(renderer, mimetype)
-	{
-		mimetype	= mimetype	|| "image/png";
-		var dataUrl	= renderer.domElement.toDataURL(mimetype);
-		return dataUrl;
-	}
-
-	/**
-	 * resize an image to another resolution while preserving aspect
-	 *
-	 * @param {String} srcUrl the url of the image to resize
-	 * @param {Number} dstWidth the destination width of the image
-	 * @param {Number} dstHeight the destination height of the image
-	 * @param {Number} callback the callback to notify once completed with callback(newImageUrl)
-	*/
-	var _aspectResize	= function(srcUrl, dstW, dstH, callback){
-		// to compute the width/height while keeping aspect
-		var cpuScaleAspect	= function(maxW, maxH, curW, curH){
-			var ratio	= curH / curW;
-			if( curW >= maxW && ratio <= 1 ){ 
-				curW	= maxW;
-				curH	= maxW * ratio;
-			}else if(curH >= maxH){
-				curH	= maxH;
-				curW	= maxH / ratio;
-			}
-			return { width: curW, height: curH };
-		}
-		// callback once the image is loaded
-		var onLoad	= function(){
-			// init the canvas
-			var canvas	= document.createElement('canvas');
-			canvas.width	= dstW;	canvas.height	= dstH;
-			var ctx		= canvas.getContext('2d');
-
-			// TODO is this needed
-			ctx.fillStyle	= "black";
-			ctx.fillRect(0, 0, canvas.width, canvas.height);
-
-			// scale the image while preserving the aspect
-			var scaled	= cpuScaleAspect(canvas.width, canvas.height, image.width, image.height);
-
-			// actually draw the image on canvas
-			var offsetX	= (canvas.width  - scaled.width )/2;
-			var offsetY	= (canvas.height - scaled.height)/2;
-			ctx.drawImage(image, offsetX, offsetY, scaled.width, scaled.height);
-
-			// dump the canvas to an URL		
-			var mimetype	= "image/png";
-			var newDataUrl	= canvas.toDataURL(mimetype);
-			// notify the url to the caller
-			callback && callback(newDataUrl)
-		}.bind(this);
-
-		// Create new Image object
-		var image 	= new Image();
-		image.onload	= onLoad;
-		image.src	= srcUrl;
-	}
-	
-
-	// Super cooked function: THREEx.Screenshot.bindKey(renderer)
-	// and you are done to get screenshot on your demo
-
-	/**
-	 * Bind a key to renderer screenshot
-	*/
-	var bindKey	= function(renderer, opts){
-		// handle parameters
-		opts		= opts		|| {};
-		var charCode	= opts.charCode	|| 'p'.charCodeAt(0);
-		var width	= opts.width;
-		var height	= opts.height;
-		var callback	= opts.callback	|| function(url){
-			window.open(url, "name-"+Math.random());
-		};
-
-		// callback to handle keypress
-		var onKeyPress	= function(event){
-		    // return now if the KeyPress isnt for the proper charCode
-			if( event.which !== charCode )	return;
-			// get the renderer output
-			var dataUrl	= this.toDataURL(renderer);
-			
-			if( width === undefined && height === undefined ){
-				callback( dataUrl )
-			}else{
-				// resize it and notify the callback
-				// * resize == async so if callback is a window open, it triggers the pop blocker
-				_aspectResize(dataUrl, width, height, callback);				
-			}
-		}.bind(this);
-
-		// listen to keypress
-		// NOTE: for firefox it seems mandatory to listen to document directly
-		document.addEventListener('keypress', onKeyPress, false);
-
-		return {
-			unbind	: function(){
-				document.removeEventListener('keypress', onKeyPress, false);
-			}
-		};
-	}
-
-	// export it	
-	THREEx.Screenshot	= {
-		toDataURL	: toDataURL,
-		bindKey		: bindKey
-	};
-})();
\ No newline at end of file
diff --git a/emperor/support_files/js/Three.js b/emperor/support_files/js/Three.js
deleted file mode 100644
index 3d249dd..0000000
--- a/emperor/support_files/js/Three.js
+++ /dev/null
@@ -1,37637 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author Larry Battle / http://bateru.com/news
- */
-
-var THREE = THREE || { REVISION: '58' };
-
-self.console = self.console || {
-
-	info: function () {},
-	log: function () {},
-	debug: function () {},
-	warn: function () {},
-	error: function () {}
-
-};
-
-self.Int32Array = self.Int32Array || Array;
-self.Float32Array = self.Float32Array || Array;
-
-String.prototype.trim = String.prototype.trim || function () {
-
-	return this.replace( /^\s+|\s+$/g, '' );
-
-};
-
-// based on https://github.com/documentcloud/underscore/blob/bf657be243a075b5e72acc8a83e6f12a564d8f55/underscore.js#L767
-THREE.extend = function ( obj, source ) {
-
-	// ECMAScript5 compatibility based on: http://www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible/
-	if ( Object.keys ) {
-
-		var keys = Object.keys( source );
-
-		for (var i = 0, il = keys.length; i < il; i++) {
-
-			var prop = keys[i];
-			Object.defineProperty( obj, prop, Object.getOwnPropertyDescriptor( source, prop ) );
-
-		}
-
-	} else {
-
-		var safeHasOwnProperty = {}.hasOwnProperty;
-
-		for ( var prop in source ) {
-
-			if ( safeHasOwnProperty.call( source, prop ) ) {
-
-				obj[prop] = source[prop];
-
-			}
-
-		}
-
-	}
-
-	return obj;
-
-};
-
-// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
-// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
-
-// requestAnimationFrame polyfill by Erik Möller
-// fixes from Paul Irish and Tino Zijdel
-
-( function () {
-
-	var lastTime = 0;
-	var vendors = [ 'ms', 'moz', 'webkit', 'o' ];
-
-	for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++ x ) {
-
-		window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ];
-		window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ];
-
-	}
-
-	if ( window.requestAnimationFrame === undefined ) {
-
-		window.requestAnimationFrame = function ( callback ) {
-
-			var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
-			var id = window.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall );
-			lastTime = currTime + timeToCall;
-			return id;
-
-		};
-
-	}
-
-	window.cancelAnimationFrame = window.cancelAnimationFrame || function ( id ) { window.clearTimeout( id ) };
-
-}() );
-
-// GL STATE CONSTANTS
-
-THREE.CullFaceNone = 0;
-THREE.CullFaceBack = 1;
-THREE.CullFaceFront = 2;
-THREE.CullFaceFrontBack = 3;
-
-THREE.FrontFaceDirectionCW = 0;
-THREE.FrontFaceDirectionCCW = 1;
-
-// SHADOWING TYPES
-
-THREE.BasicShadowMap = 0;
-THREE.PCFShadowMap = 1;
-THREE.PCFSoftShadowMap = 2;
-
-// MATERIAL CONSTANTS
-
-// side
-
-THREE.FrontSide = 0;
-THREE.BackSide = 1;
-THREE.DoubleSide = 2;
-
-// shading
-
-THREE.NoShading = 0;
-THREE.FlatShading = 1;
-THREE.SmoothShading = 2;
-
-// colors
-
-THREE.NoColors = 0;
-THREE.FaceColors = 1;
-THREE.VertexColors = 2;
-
-// blending modes
-
-THREE.NoBlending = 0;
-THREE.NormalBlending = 1;
-THREE.AdditiveBlending = 2;
-THREE.SubtractiveBlending = 3;
-THREE.MultiplyBlending = 4;
-THREE.CustomBlending = 5;
-
-// custom blending equations
-// (numbers start from 100 not to clash with other
-//  mappings to OpenGL constants defined in Texture.js)
-
-THREE.AddEquation = 100;
-THREE.SubtractEquation = 101;
-THREE.ReverseSubtractEquation = 102;
-
-// custom blending destination factors
-
-THREE.ZeroFactor = 200;
-THREE.OneFactor = 201;
-THREE.SrcColorFactor = 202;
-THREE.OneMinusSrcColorFactor = 203;
-THREE.SrcAlphaFactor = 204;
-THREE.OneMinusSrcAlphaFactor = 205;
-THREE.DstAlphaFactor = 206;
-THREE.OneMinusDstAlphaFactor = 207;
-
-// custom blending source factors
-
-//THREE.ZeroFactor = 200;
-//THREE.OneFactor = 201;
-//THREE.SrcAlphaFactor = 204;
-//THREE.OneMinusSrcAlphaFactor = 205;
-//THREE.DstAlphaFactor = 206;
-//THREE.OneMinusDstAlphaFactor = 207;
-THREE.DstColorFactor = 208;
-THREE.OneMinusDstColorFactor = 209;
-THREE.SrcAlphaSaturateFactor = 210;
-
-
-// TEXTURE CONSTANTS
-
-THREE.MultiplyOperation = 0;
-THREE.MixOperation = 1;
-THREE.AddOperation = 2;
-
-// Mapping modes
-
-THREE.UVMapping = function () {};
-
-THREE.CubeReflectionMapping = function () {};
-THREE.CubeRefractionMapping = function () {};
-
-THREE.SphericalReflectionMapping = function () {};
-THREE.SphericalRefractionMapping = function () {};
-
-// Wrapping modes
-
-THREE.RepeatWrapping = 1000;
-THREE.ClampToEdgeWrapping = 1001;
-THREE.MirroredRepeatWrapping = 1002;
-
-// Filters
-
-THREE.NearestFilter = 1003;
-THREE.NearestMipMapNearestFilter = 1004;
-THREE.NearestMipMapLinearFilter = 1005;
-THREE.LinearFilter = 1006;
-THREE.LinearMipMapNearestFilter = 1007;
-THREE.LinearMipMapLinearFilter = 1008;
-
-// Data types
-
-THREE.UnsignedByteType = 1009;
-THREE.ByteType = 1010;
-THREE.ShortType = 1011;
-THREE.UnsignedShortType = 1012;
-THREE.IntType = 1013;
-THREE.UnsignedIntType = 1014;
-THREE.FloatType = 1015;
-
-// Pixel types
-
-//THREE.UnsignedByteType = 1009;
-THREE.UnsignedShort4444Type = 1016;
-THREE.UnsignedShort5551Type = 1017;
-THREE.UnsignedShort565Type = 1018;
-
-// Pixel formats
-
-THREE.AlphaFormat = 1019;
-THREE.RGBFormat = 1020;
-THREE.RGBAFormat = 1021;
-THREE.LuminanceFormat = 1022;
-THREE.LuminanceAlphaFormat = 1023;
-
-// Compressed texture formats
-
-THREE.RGB_S3TC_DXT1_Format = 2001;
-THREE.RGBA_S3TC_DXT1_Format = 2002;
-THREE.RGBA_S3TC_DXT3_Format = 2003;
-THREE.RGBA_S3TC_DXT5_Format = 2004;
-
-/*
-// Potential future PVRTC compressed texture formats
-THREE.RGB_PVRTC_4BPPV1_Format = 2100;
-THREE.RGB_PVRTC_2BPPV1_Format = 2101;
-THREE.RGBA_PVRTC_4BPPV1_Format = 2102;
-THREE.RGBA_PVRTC_2BPPV1_Format = 2103;
-*/
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Color = function ( value ) {
-
-	if ( value !== undefined ) this.set( value );
-
-	return this;
-
-};
-
-THREE.Color.prototype = {
-
-	constructor: THREE.Color,
-
-	r: 1, g: 1, b: 1,
-
-	set: function ( value ) {
-
-		if ( value instanceof THREE.Color ) {
-
-			this.copy( value );
-
-		} else if ( typeof value === 'number' ) {
-
-			this.setHex( value );
-
-		} else if ( typeof value === 'string' ) {
-
-			this.setStyle( value );
-
-		}
-
-		return this;
-
-	},
-
-	setHex: function ( hex ) {
-
-		hex = Math.floor( hex );
-
-		this.r = ( hex >> 16 & 255 ) / 255;
-		this.g = ( hex >> 8 & 255 ) / 255;
-		this.b = ( hex & 255 ) / 255;
-
-		return this;
-
-	},
-
-	setRGB: function ( r, g, b ) {
-
-		this.r = r;
-		this.g = g;
-		this.b = b;
-
-		return this;
-
-	},
-
-	setHSL: function ( h, s, l ) {
-
-		// h,s,l ranges are in 0.0 - 1.0
-
-		if ( s === 0 ) {
-
-			this.r = this.g = this.b = l;
-
-		} else {
-
-			var hue2rgb = function ( p, q, t ) {
-
-				if ( t < 0 ) t += 1;
-				if ( t > 1 ) t -= 1;
-				if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
-				if ( t < 1 / 2 ) return q;
-				if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
-				return p;
-
-			};
-
-			var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
-			var q = ( 2 * l ) - p;
-
-			this.r = hue2rgb( q, p, h + 1 / 3 );
-			this.g = hue2rgb( q, p, h );
-			this.b = hue2rgb( q, p, h - 1 / 3 );
-
-		}
-
-		return this;
-
-	},
-
-	setStyle: function ( style ) {
-
-		// rgb(255,0,0)
-
-		if ( /^rgb\((\d+),(\d+),(\d+)\)$/i.test( style ) ) {
-
-			var color = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec( style );
-
-			this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
-			this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
-			this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
-
-			return this;
-
-		}
-
-		// rgb(100%,0%,0%)
-
-		if ( /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test( style ) ) {
-
-			var color = /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec( style );
-
-			this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
-			this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
-			this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
-
-			return this;
-
-		}
-
-		// #ff0000
-
-		if ( /^\#([0-9a-f]{6})$/i.test( style ) ) {
-
-			var color = /^\#([0-9a-f]{6})$/i.exec( style );
-
-			this.setHex( parseInt( color[ 1 ], 16 ) );
-
-			return this;
-
-		}
-
-		// #f00
-
-		if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) {
-
-			var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style );
-
-			this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) );
-
-			return this;
-
-		}
-
-		// red
-
-		if ( /^(\w+)$/i.test( style ) ) {
-
-			this.setHex( THREE.ColorKeywords[ style ] );
-
-			return this;
-
-		}
-
-
-	},
-
-	copy: function ( color ) {
-
-		this.r = color.r;
-		this.g = color.g;
-		this.b = color.b;
-
-		return this;
-
-	},
-
-	copyGammaToLinear: function ( color ) {
-
-		this.r = color.r * color.r;
-		this.g = color.g * color.g;
-		this.b = color.b * color.b;
-
-		return this;
-
-	},
-
-	copyLinearToGamma: function ( color ) {
-
-		this.r = Math.sqrt( color.r );
-		this.g = Math.sqrt( color.g );
-		this.b = Math.sqrt( color.b );
-
-		return this;
-
-	},
-
-	convertGammaToLinear: function () {
-
-		var r = this.r, g = this.g, b = this.b;
-
-		this.r = r * r;
-		this.g = g * g;
-		this.b = b * b;
-
-		return this;
-
-	},
-
-	convertLinearToGamma: function () {
-
-		this.r = Math.sqrt( this.r );
-		this.g = Math.sqrt( this.g );
-		this.b = Math.sqrt( this.b );
-
-		return this;
-
-	},
-
-	getHex: function () {
-
-		return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
-
-	},
-
-	getHexString: function () {
-
-		return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
-
-	},
-
-	getHSL: function () {
-
-		var hsl = { h: 0, s: 0, l: 0 };
-
-		return function () {
-
-			// h,s,l ranges are in 0.0 - 1.0
-
-			var r = this.r, g = this.g, b = this.b;
-
-			var max = Math.max( r, g, b );
-			var min = Math.min( r, g, b );
-
-			var hue, saturation;
-			var lightness = ( min + max ) / 2.0;
-
-			if ( min === max ) {
-
-				hue = 0;
-				saturation = 0;
-
-			} else {
-
-				var delta = max - min;
-
-				saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
-
-				switch ( max ) {
-
-					case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
-					case g: hue = ( b - r ) / delta + 2; break;
-					case b: hue = ( r - g ) / delta + 4; break;
-
-				}
-
-				hue /= 6;
-
-			}
-
-			hsl.h = hue;
-			hsl.s = saturation;
-			hsl.l = lightness;
-
-			return hsl;
-
-		};
-
-	}(),
-
-	getStyle: function () {
-
-		return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
-
-	},
-
-	offsetHSL: function ( h, s, l ) {
-
-		var hsl = this.getHSL();
-
-		hsl.h += h; hsl.s += s; hsl.l += l;
-
-		this.setHSL( hsl.h, hsl.s, hsl.l );
-
-		return this;
-
-	},
-
-	add: function ( color ) {
-
-		this.r += color.r;
-		this.g += color.g;
-		this.b += color.b;
-
-		return this;
-
-	},
-
-	addColors: function ( color1, color2 ) {
-
-		this.r = color1.r + color2.r;
-		this.g = color1.g + color2.g;
-		this.b = color1.b + color2.b;
-
-		return this;
-
-	},
-
-	addScalar: function ( s ) {
-
-		this.r += s;
-		this.g += s;
-		this.b += s;
-
-		return this;
-
-	},
-
-	multiply: function ( color ) {
-
-		this.r *= color.r;
-		this.g *= color.g;
-		this.b *= color.b;
-
-		return this;
-
-	},
-
-	multiplyScalar: function ( s ) {
-
-		this.r *= s;
-		this.g *= s;
-		this.b *= s;
-
-		return this;
-
-	},
-
-	lerp: function ( color, alpha ) {
-
-		this.r += ( color.r - this.r ) * alpha;
-		this.g += ( color.g - this.g ) * alpha;
-		this.b += ( color.b - this.b ) * alpha;
-
-		return this;
-
-	},
-
-	equals: function ( c ) {
-
-		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Color().setRGB( this.r, this.g, this.b );
-
-	}
-
-};
-
-THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF,
-"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2,
-"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50,
-"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B,
-"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B,
-"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F,
-"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3,
-"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222,
-"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700,
-"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4,
-"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00,
-"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3,
-"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA,
-"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32,
-"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3,
-"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC,
-"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD,
-"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6,
-"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9,
-"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F,
-"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE,
-"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA,
-"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0,
-"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 };
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author WestLangley / http://github.com/WestLangley
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Quaternion = function( x, y, z, w ) {
-
-	this.x = x || 0;
-	this.y = y || 0;
-	this.z = z || 0;
-	this.w = ( w !== undefined ) ? w : 1;
-
-};
-
-THREE.Quaternion.prototype = {
-
-	constructor: THREE.Quaternion,
-
-	set: function ( x, y, z, w ) {
-
-		this.x = x;
-		this.y = y;
-		this.z = z;
-		this.w = w;
-
-		return this;
-
-	},
-
-	copy: function ( q ) {
-
-		this.x = q.x;
-		this.y = q.y;
-		this.z = q.z;
-		this.w = q.w;
-
-		return this;
-
-	},
-
-	setFromEuler: function ( v, order ) {
-
-		// http://www.mathworks.com/matlabcentral/fileexchange/
-		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
-		//	content/SpinCalc.m
-
-		var c1 = Math.cos( v.x / 2 );
-		var c2 = Math.cos( v.y / 2 );
-		var c3 = Math.cos( v.z / 2 );
-		var s1 = Math.sin( v.x / 2 );
-		var s2 = Math.sin( v.y / 2 );
-		var s3 = Math.sin( v.z / 2 );
-
-		if ( order === undefined || order === 'XYZ' ) {
-
-			this.x = s1 * c2 * c3 + c1 * s2 * s3;
-			this.y = c1 * s2 * c3 - s1 * c2 * s3;
-			this.z = c1 * c2 * s3 + s1 * s2 * c3;
-			this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
-		} else if ( order === 'YXZ' ) {
-
-			this.x = s1 * c2 * c3 + c1 * s2 * s3;
-			this.y = c1 * s2 * c3 - s1 * c2 * s3;
-			this.z = c1 * c2 * s3 - s1 * s2 * c3;
-			this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
-		} else if ( order === 'ZXY' ) {
-
-			this.x = s1 * c2 * c3 - c1 * s2 * s3;
-			this.y = c1 * s2 * c3 + s1 * c2 * s3;
-			this.z = c1 * c2 * s3 + s1 * s2 * c3;
-			this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
-		} else if ( order === 'ZYX' ) {
-
-			this.x = s1 * c2 * c3 - c1 * s2 * s3;
-			this.y = c1 * s2 * c3 + s1 * c2 * s3;
-			this.z = c1 * c2 * s3 - s1 * s2 * c3;
-			this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
-		} else if ( order === 'YZX' ) {
-
-			this.x = s1 * c2 * c3 + c1 * s2 * s3;
-			this.y = c1 * s2 * c3 + s1 * c2 * s3;
-			this.z = c1 * c2 * s3 - s1 * s2 * c3;
-			this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
-		} else if ( order === 'XZY' ) {
-
-			this.x = s1 * c2 * c3 - c1 * s2 * s3;
-			this.y = c1 * s2 * c3 - s1 * c2 * s3;
-			this.z = c1 * c2 * s3 + s1 * s2 * c3;
-			this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
-		}
-
-		return this;
-
-	},
-
-	setFromAxisAngle: function ( axis, angle ) {
-
-		// from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
-		// axis have to be normalized
-
-		var halfAngle = angle / 2,
-			s = Math.sin( halfAngle );
-
-		this.x = axis.x * s;
-		this.y = axis.y * s;
-		this.z = axis.z * s;
-		this.w = Math.cos( halfAngle );
-
-		return this;
-
-	},
-
-	setFromRotationMatrix: function ( m ) {
-
-		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
-
-		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
-
-		var te = m.elements,
-
-			m11 = te[0], m12 = te[4], m13 = te[8],
-			m21 = te[1], m22 = te[5], m23 = te[9],
-			m31 = te[2], m32 = te[6], m33 = te[10],
-
-			trace = m11 + m22 + m33,
-			s;
-
-		if ( trace > 0 ) {
-
-			s = 0.5 / Math.sqrt( trace + 1.0 );
-
-			this.w = 0.25 / s;
-			this.x = ( m32 - m23 ) * s;
-			this.y = ( m13 - m31 ) * s;
-			this.z = ( m21 - m12 ) * s;
-
-		} else if ( m11 > m22 && m11 > m33 ) {
-
-			s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
-
-			this.w = (m32 - m23 ) / s;
-			this.x = 0.25 * s;
-			this.y = (m12 + m21 ) / s;
-			this.z = (m13 + m31 ) / s;
-
-		} else if ( m22 > m33 ) {
-
-			s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
-
-			this.w = (m13 - m31 ) / s;
-			this.x = (m12 + m21 ) / s;
-			this.y = 0.25 * s;
-			this.z = (m23 + m32 ) / s;
-
-		} else {
-
-			s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
-
-			this.w = ( m21 - m12 ) / s;
-			this.x = ( m13 + m31 ) / s;
-			this.y = ( m23 + m32 ) / s;
-			this.z = 0.25 * s;
-
-		}
-
-		return this;
-
-	},
-
-	inverse: function () {
-
-		this.conjugate().normalize();
-
-		return this;
-
-	},
-
-	conjugate: function () {
-
-		this.x *= -1;
-		this.y *= -1;
-		this.z *= -1;
-
-		return this;
-
-	},
-
-	lengthSq: function () {
-
-		return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
-
-	},
-
-	length: function () {
-
-		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
-
-	},
-
-	normalize: function () {
-
-		var l = this.length();
-
-		if ( l === 0 ) {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-			this.w = 1;
-
-		} else {
-
-			l = 1 / l;
-
-			this.x = this.x * l;
-			this.y = this.y * l;
-			this.z = this.z * l;
-			this.w = this.w * l;
-
-		}
-
-		return this;
-
-	},
-
-	multiply: function ( q, p ) {
-
-		if ( p !== undefined ) {
-
-			console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
-			return this.multiplyQuaternions( q, p );
-
-		}
-
-		return this.multiplyQuaternions( this, q );
-
-	},
-
-	multiplyQuaternions: function ( a, b ) {
-
-		// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
-
-		var qax = a.x, qay = a.y, qaz = a.z, qaw = a.w;
-		var qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w;
-
-		this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
-		this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
-		this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
-		this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
-
-		return this;
-
-	},
-
-	multiplyVector3: function ( vector ) {
-
-		console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
-		return vector.applyQuaternion( this );
-
-	},
-
-	slerp: function ( qb, t ) {
-
-		var x = this.x, y = this.y, z = this.z, w = this.w;
-
-		// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
-
-		var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
-
-		if ( cosHalfTheta < 0 ) {
-
-			this.w = -qb.w;
-			this.x = -qb.x;
-			this.y = -qb.y;
-			this.z = -qb.z;
-
-			cosHalfTheta = -cosHalfTheta;
-
-		} else {
-
-			this.copy( qb );
-
-		}
-
-		if ( cosHalfTheta >= 1.0 ) {
-
-			this.w = w;
-			this.x = x;
-			this.y = y;
-			this.z = z;
-
-			return this;
-
-		}
-
-		var halfTheta = Math.acos( cosHalfTheta );
-		var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
-
-		if ( Math.abs( sinHalfTheta ) < 0.001 ) {
-
-			this.w = 0.5 * ( w + this.w );
-			this.x = 0.5 * ( x + this.x );
-			this.y = 0.5 * ( y + this.y );
-			this.z = 0.5 * ( z + this.z );
-
-			return this;
-
-		}
-
-		var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
-		ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
-
-		this.w = ( w * ratioA + this.w * ratioB );
-		this.x = ( x * ratioA + this.x * ratioB );
-		this.y = ( y * ratioA + this.y * ratioB );
-		this.z = ( z * ratioA + this.z * ratioB );
-
-		return this;
-
-	},
-
-	equals: function ( v ) {
-
-		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
-
-	},
-
-	fromArray: function ( array ) {
-
-		this.x = array[ 0 ];
-		this.y = array[ 1 ];
-		this.z = array[ 2 ];
-		this.w = array[ 3 ];
-
-		return this;
-
-	},
-
-	toArray: function () {
-
-		return [ this.x, this.y, this.z, this.w ];
-
-	},
-
-	clone: function () {
-
-		return new THREE.Quaternion( this.x, this.y, this.z, this.w );
-
-	}
-
-};
-
-THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
-
-	return qm.copy( qa ).slerp( qb, t );
-
-}
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author philogb / http://blog.thejit.org/
- * @author egraether / http://egraether.com/
- * @author zz85 / http://www.lab4games.net/zz85/blog
- */
-
-THREE.Vector2 = function ( x, y ) {
-
-	this.x = x || 0;
-	this.y = y || 0;
-
-};
-
-THREE.Vector2.prototype = {
-
-	constructor: THREE.Vector2,
-
-	set: function ( x, y ) {
-
-		this.x = x;
-		this.y = y;
-
-		return this;
-
-	},
-
-	setX: function ( x ) {
-
-		this.x = x;
-
-		return this;
-
-	},
-
-	setY: function ( y ) {
-
-		this.y = y;
-
-		return this;
-
-	},
-
-
-	setComponent: function ( index, value ) {
-
-		switch ( index ) {
-
-			case 0: this.x = value; break;
-			case 1: this.y = value; break;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	getComponent: function ( index ) {
-
-		switch ( index ) {
-
-			case 0: return this.x;
-			case 1: return this.y;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	copy: function ( v ) {
-
-		this.x = v.x;
-		this.y = v.y;
-
-		return this;
-
-	},
-
-	add: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
-			return this.addVectors( v, w );
-
-		}
-
-		this.x += v.x;
-		this.y += v.y;
-
-		return this;
-
-	},
-
-	addVectors: function ( a, b ) {
-
-		this.x = a.x + b.x;
-		this.y = a.y + b.y;
-
-		return this;
-
-	},
-
-	addScalar: function ( s ) {
-
-		this.x += s;
-		this.y += s;
-
-		return this;
-
-	},
-
-	sub: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
-			return this.subVectors( v, w );
-
-		}
-
-		this.x -= v.x;
-		this.y -= v.y;
-
-		return this;
-
-	},
-
-	subVectors: function ( a, b ) {
-
-		this.x = a.x - b.x;
-		this.y = a.y - b.y;
-
-		return this;
-
-	},
-
-	multiplyScalar: function ( s ) {
-
-		this.x *= s;
-		this.y *= s;
-
-		return this;
-
-	},
-
-	divideScalar: function ( s ) {
-
-		if ( s !== 0 ) {
-
-			this.x /= s;
-			this.y /= s;
-
-		} else {
-
-			this.set( 0, 0 );
-
-		}
-
-		return this;
-
-	},
-
-	min: function ( v ) {
-
-		if ( this.x > v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y > v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		return this;
-
-	},
-
-	max: function ( v ) {
-
-		if ( this.x < v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y < v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		return this;
-
-	},
-
-	clamp: function ( min, max ) {
-
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
-
-		if ( this.x < min.x ) {
-
-			this.x = min.x;
-
-		} else if ( this.x > max.x ) {
-
-			this.x = max.x;
-
-		}
-
-		if ( this.y < min.y ) {
-
-			this.y = min.y;
-
-		} else if ( this.y > max.y ) {
-
-			this.y = max.y;
-
-		}
-
-		return this;
-
-	},
-
-	negate: function() {
-
-		return this.multiplyScalar( - 1 );
-
-	},
-
-	dot: function ( v ) {
-
-		return this.x * v.x + this.y * v.y;
-
-	},
-
-	lengthSq: function () {
-
-		return this.x * this.x + this.y * this.y;
-
-	},
-
-	length: function () {
-
-		return Math.sqrt( this.x * this.x + this.y * this.y );
-
-	},
-
-	normalize: function () {
-
-		return this.divideScalar( this.length() );
-
-	},
-
-	distanceTo: function ( v ) {
-
-		return Math.sqrt( this.distanceToSquared( v ) );
-
-	},
-
-	distanceToSquared: function ( v ) {
-
-		var dx = this.x - v.x, dy = this.y - v.y;
-		return dx * dx + dy * dy;
-
-	},
-
-	setLength: function ( l ) {
-
-		var oldLength = this.length();
-
-		if ( oldLength !== 0 && l !== oldLength ) {
-
-			this.multiplyScalar( l / oldLength );
-		}
-
-		return this;
-
-	},
-
-	lerp: function ( v, alpha ) {
-
-		this.x += ( v.x - this.x ) * alpha;
-		this.y += ( v.y - this.y ) * alpha;
-
-		return this;
-
-	},
-
-	equals: function( v ) {
-
-		return ( ( v.x === this.x ) && ( v.y === this.y ) );
-
-	},
-
-	fromArray: function ( array ) {
-
-		this.x = array[ 0 ];
-		this.y = array[ 1 ];
-
-		return this;
-
-	},
-
-	toArray: function () {
-
-		return [ this.x, this.y ];
-
-	},
-
-	clone: function () {
-
-		return new THREE.Vector2( this.x, this.y );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author *kile / http://kile.stravaganza.org/
- * @author philogb / http://blog.thejit.org/
- * @author mikael emtinger / http://gomo.se/
- * @author egraether / http://egraether.com/
- * @author WestLangley / http://github.com/WestLangley
- */
-
-THREE.Vector3 = function ( x, y, z ) {
-
-	this.x = x || 0;
-	this.y = y || 0;
-	this.z = z || 0;
-
-};
-
-THREE.Vector3.prototype = {
-
-	constructor: THREE.Vector3,
-
-	set: function ( x, y, z ) {
-
-		this.x = x;
-		this.y = y;
-		this.z = z;
-
-		return this;
-
-	},
-
-	setX: function ( x ) {
-
-		this.x = x;
-
-		return this;
-
-	},
-
-	setY: function ( y ) {
-
-		this.y = y;
-
-		return this;
-
-	},
-
-	setZ: function ( z ) {
-
-		this.z = z;
-
-		return this;
-
-	},
-
-	setComponent: function ( index, value ) {
-
-		switch ( index ) {
-
-			case 0: this.x = value; break;
-			case 1: this.y = value; break;
-			case 2: this.z = value; break;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	getComponent: function ( index ) {
-
-		switch ( index ) {
-
-			case 0: return this.x;
-			case 1: return this.y;
-			case 2: return this.z;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	copy: function ( v ) {
-
-		this.x = v.x;
-		this.y = v.y;
-		this.z = v.z;
-
-		return this;
-
-	},
-
-	add: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
-			return this.addVectors( v, w );
-
-		}
-
-		this.x += v.x;
-		this.y += v.y;
-		this.z += v.z;
-
-		return this;
-
-	},
-
-	addScalar: function ( s ) {
-
-		this.x += s;
-		this.y += s;
-		this.z += s;
-
-		return this;
-
-	},
-
-	addVectors: function ( a, b ) {
-
-		this.x = a.x + b.x;
-		this.y = a.y + b.y;
-		this.z = a.z + b.z;
-
-		return this;
-
-	},
-
-	sub: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
-			return this.subVectors( v, w );
-
-		}
-
-		this.x -= v.x;
-		this.y -= v.y;
-		this.z -= v.z;
-
-		return this;
-
-	},
-
-	subVectors: function ( a, b ) {
-
-		this.x = a.x - b.x;
-		this.y = a.y - b.y;
-		this.z = a.z - b.z;
-
-		return this;
-
-	},
-
-	multiply: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
-			return this.multiplyVectors( v, w );
-
-		}
-
-		this.x *= v.x;
-		this.y *= v.y;
-		this.z *= v.z;
-
-		return this;
-
-	},
-
-	multiplyScalar: function ( s ) {
-
-		this.x *= s;
-		this.y *= s;
-		this.z *= s;
-
-		return this;
-
-	},
-
-	multiplyVectors: function ( a, b ) {
-
-		this.x = a.x * b.x;
-		this.y = a.y * b.y;
-		this.z = a.z * b.z;
-
-		return this;
-
-	},
-
-	applyMatrix3: function ( m ) {
-
-		var x = this.x;
-		var y = this.y;
-		var z = this.z;
-
-		var e = m.elements;
-
-		this.x = e[0] * x + e[3] * y + e[6] * z;
-		this.y = e[1] * x + e[4] * y + e[7] * z;
-		this.z = e[2] * x + e[5] * y + e[8] * z;
-
-		return this;
-
-	},
-
-	applyMatrix4: function ( m ) {
-
-		// input: THREE.Matrix4 affine matrix
-
-		var x = this.x, y = this.y, z = this.z;
-
-		var e = m.elements;
-
-		this.x = e[0] * x + e[4] * y + e[8]  * z + e[12];
-		this.y = e[1] * x + e[5] * y + e[9]  * z + e[13];
-		this.z = e[2] * x + e[6] * y + e[10] * z + e[14];
-
-		return this;
-
-	},
-
-	applyProjection: function ( m ) {
-
-		// input: THREE.Matrix4 projection matrix
-
-		var x = this.x, y = this.y, z = this.z;
-
-		var e = m.elements;
-		var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide
-
-		this.x = ( e[0] * x + e[4] * y + e[8]  * z + e[12] ) * d;
-		this.y = ( e[1] * x + e[5] * y + e[9]  * z + e[13] ) * d;
-		this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d;
-
-		return this;
-
-	},
-
-	applyQuaternion: function ( q ) {
-
-		var x = this.x;
-		var y = this.y;
-		var z = this.z;
-
-		var qx = q.x;
-		var qy = q.y;
-		var qz = q.z;
-		var qw = q.w;
-
-		// calculate quat * vector
-
-		var ix =  qw * x + qy * z - qz * y;
-		var iy =  qw * y + qz * x - qx * z;
-		var iz =  qw * z + qx * y - qy * x;
-		var iw = -qx * x - qy * y - qz * z;
-
-		// calculate result * inverse quat
-
-		this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
-		this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
-		this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
-
-		return this;
-
-	},
-
-	transformDirection: function ( m ) {
-
-		// input: THREE.Matrix4 affine matrix
-		// vector interpreted as a direction
-
-		var x = this.x, y = this.y, z = this.z;
-
-		var e = m.elements;
-
-		this.x = e[0] * x + e[4] * y + e[8]  * z;
-		this.y = e[1] * x + e[5] * y + e[9]  * z;
-		this.z = e[2] * x + e[6] * y + e[10] * z;
-
-		this.normalize();
-
-		return this;
-
-	},
-
-	divide: function ( v ) {
-
-		this.x /= v.x;
-		this.y /= v.y;
-		this.z /= v.z;
-
-		return this;
-
-	},
-
-	divideScalar: function ( s ) {
-
-		if ( s !== 0 ) {
-
-			this.x /= s;
-			this.y /= s;
-			this.z /= s;
-
-		} else {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-
-		}
-
-		return this;
-
-	},
-
-	min: function ( v ) {
-
-		if ( this.x > v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y > v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		if ( this.z > v.z ) {
-
-			this.z = v.z;
-
-		}
-
-		return this;
-
-	},
-
-	max: function ( v ) {
-
-		if ( this.x < v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y < v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		if ( this.z < v.z ) {
-
-			this.z = v.z;
-
-		}
-
-		return this;
-
-	},
-
-	clamp: function ( min, max ) {
-
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
-
-		if ( this.x < min.x ) {
-
-			this.x = min.x;
-
-		} else if ( this.x > max.x ) {
-
-			this.x = max.x;
-
-		}
-
-		if ( this.y < min.y ) {
-
-			this.y = min.y;
-
-		} else if ( this.y > max.y ) {
-
-			this.y = max.y;
-
-		}
-
-		if ( this.z < min.z ) {
-
-			this.z = min.z;
-
-		} else if ( this.z > max.z ) {
-
-			this.z = max.z;
-
-		}
-
-		return this;
-
-	},
-
-	negate: function () {
-
-		return this.multiplyScalar( - 1 );
-
-	},
-
-	dot: function ( v ) {
-
-		return this.x * v.x + this.y * v.y + this.z * v.z;
-
-	},
-
-	lengthSq: function () {
-
-		return this.x * this.x + this.y * this.y + this.z * this.z;
-
-	},
-
-	length: function () {
-
-		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
-
-	},
-
-	lengthManhattan: function () {
-
-		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
-
-	},
-
-	normalize: function () {
-
-		return this.divideScalar( this.length() );
-
-	},
-
-	setLength: function ( l ) {
-
-		var oldLength = this.length();
-
-		if ( oldLength !== 0 && l !== oldLength  ) {
-
-			this.multiplyScalar( l / oldLength );
-		}
-
-		return this;
-
-	},
-
-	lerp: function ( v, alpha ) {
-
-		this.x += ( v.x - this.x ) * alpha;
-		this.y += ( v.y - this.y ) * alpha;
-		this.z += ( v.z - this.z ) * alpha;
-
-		return this;
-
-	},
-
-	cross: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
-			return this.crossVectors( v, w );
-
-		}
-
-		var x = this.x, y = this.y, z = this.z;
-
-		this.x = y * v.z - z * v.y;
-		this.y = z * v.x - x * v.z;
-		this.z = x * v.y - y * v.x;
-
-		return this;
-
-	},
-
-	crossVectors: function ( a, b ) {
-
-		this.x = a.y * b.z - a.z * b.y;
-		this.y = a.z * b.x - a.x * b.z;
-		this.z = a.x * b.y - a.y * b.x;
-
-		return this;
-
-	},
-
-	angleTo: function ( v ) {
-
-		var theta = this.dot( v ) / ( this.length() * v.length() );
-
-		// clamp, to handle numerical problems
-
-		return Math.acos( THREE.Math.clamp( theta, -1, 1 ) );
-
-	},
-
-	distanceTo: function ( v ) {
-
-		return Math.sqrt( this.distanceToSquared( v ) );
-
-	},
-
-	distanceToSquared: function ( v ) {
-
-		var dx = this.x - v.x;
-		var dy = this.y - v.y;
-		var dz = this.z - v.z;
-
-		return dx * dx + dy * dy + dz * dz;
-
-	},
-
-	setEulerFromRotationMatrix: function ( m, order ) {
-
-		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
-
-		// clamp, to handle numerical problems
-
-		function clamp( x ) {
-
-			return Math.min( Math.max( x, -1 ), 1 );
-
-		}
-
-		var te = m.elements;
-		var m11 = te[0], m12 = te[4], m13 = te[8];
-		var m21 = te[1], m22 = te[5], m23 = te[9];
-		var m31 = te[2], m32 = te[6], m33 = te[10];
-
-		if ( order === undefined || order === 'XYZ' ) {
-
-			this.y = Math.asin( clamp( m13 ) );
-
-			if ( Math.abs( m13 ) < 0.99999 ) {
-
-				this.x = Math.atan2( - m23, m33 );
-				this.z = Math.atan2( - m12, m11 );
-
-			} else {
-
-				this.x = Math.atan2( m32, m22 );
-				this.z = 0;
-
-			}
-
-		} else if ( order === 'YXZ' ) {
-
-			this.x = Math.asin( - clamp( m23 ) );
-
-			if ( Math.abs( m23 ) < 0.99999 ) {
-
-				this.y = Math.atan2( m13, m33 );
-				this.z = Math.atan2( m21, m22 );
-
-			} else {
-
-				this.y = Math.atan2( - m31, m11 );
-				this.z = 0;
-
-			}
-
-		} else if ( order === 'ZXY' ) {
-
-			this.x = Math.asin( clamp( m32 ) );
-
-			if ( Math.abs( m32 ) < 0.99999 ) {
-
-				this.y = Math.atan2( - m31, m33 );
-				this.z = Math.atan2( - m12, m22 );
-
-			} else {
-
-				this.y = 0;
-				this.z = Math.atan2( m21, m11 );
-
-			}
-
-		} else if ( order === 'ZYX' ) {
-
-			this.y = Math.asin( - clamp( m31 ) );
-
-			if ( Math.abs( m31 ) < 0.99999 ) {
-
-				this.x = Math.atan2( m32, m33 );
-				this.z = Math.atan2( m21, m11 );
-
-			} else {
-
-				this.x = 0;
-				this.z = Math.atan2( - m12, m22 );
-
-			}
-
-		} else if ( order === 'YZX' ) {
-
-			this.z = Math.asin( clamp( m21 ) );
-
-			if ( Math.abs( m21 ) < 0.99999 ) {
-
-				this.x = Math.atan2( - m23, m22 );
-				this.y = Math.atan2( - m31, m11 );
-
-			} else {
-
-				this.x = 0;
-				this.y = Math.atan2( m13, m33 );
-
-			}
-
-		} else if ( order === 'XZY' ) {
-
-			this.z = Math.asin( - clamp( m12 ) );
-
-			if ( Math.abs( m12 ) < 0.99999 ) {
-
-				this.x = Math.atan2( m32, m22 );
-				this.y = Math.atan2( m13, m11 );
-
-			} else {
-
-				this.x = Math.atan2( - m23, m33 );
-				this.y = 0;
-
-			}
-
-		}
-
-		return this;
-
-	},
-
-	setEulerFromQuaternion: function ( q, order ) {
-
-		// q is assumed to be normalized
-
-		// clamp, to handle numerical problems
-
-		function clamp( x ) {
-
-			return Math.min( Math.max( x, -1 ), 1 );
-
-		}
-
-		// http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
-
-		var sqx = q.x * q.x;
-		var sqy = q.y * q.y;
-		var sqz = q.z * q.z;
-		var sqw = q.w * q.w;
-
-		if ( order === undefined || order === 'XYZ' ) {
-
-			this.x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) );
-			this.y = Math.asin(  clamp( 2 * ( q.x * q.z + q.y * q.w ) ) );
-			this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) );
-
-		} else if ( order ===  'YXZ' ) {
-
-			this.x = Math.asin(  clamp( 2 * ( q.x * q.w - q.y * q.z ) ) );
-			this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) );
-			this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) );
-
-		} else if ( order === 'ZXY' ) {
-
-			this.x = Math.asin(  clamp( 2 * ( q.x * q.w + q.y * q.z ) ) );
-			this.y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) );
-			this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) );
-
-		} else if ( order === 'ZYX' ) {
-
-			this.x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) );
-			this.y = Math.asin(  clamp( 2 * ( q.y * q.w - q.x * q.z ) ) );
-			this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) );
-
-		} else if ( order === 'YZX' ) {
-
-			this.x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) );
-			this.y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) );
-			this.z = Math.asin(  clamp( 2 * ( q.x * q.y + q.z * q.w ) ) );
-
-		} else if ( order === 'XZY' ) {
-
-			this.x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) );
-			this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) );
-			this.z = Math.asin(  clamp( 2 * ( q.z * q.w - q.x * q.y ) ) );
-
-		}
-
-		return this;
-
-	},
-
-	getPositionFromMatrix: function ( m ) {
-
-		this.x = m.elements[12];
-		this.y = m.elements[13];
-		this.z = m.elements[14];
-
-		return this;
-
-	},
-
-	getScaleFromMatrix: function ( m ) {
-
-		var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length();
-		var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length();
-		var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length();
-
-		this.x = sx;
-		this.y = sy;
-		this.z = sz;
-
-		return this;
-	},
-
-	getColumnFromMatrix: function ( index, matrix ) {
-
-		var offset = index * 4;
-
-		var me = matrix.elements;
-
-		this.x = me[ offset ];
-		this.y = me[ offset + 1 ];
-		this.z = me[ offset + 2 ];
-
-		return this;
-
-	},
-
-	equals: function ( v ) {
-
-		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
-
-	},
-
-	fromArray: function ( array ) {
-
-		this.x = array[ 0 ];
-		this.y = array[ 1 ];
-		this.z = array[ 2 ];
-
-		return this;
-
-	},
-
-	toArray: function () {
-
-		return [ this.x, this.y, this.z ];
-
-	},
-
-	clone: function () {
-
-		return new THREE.Vector3( this.x, this.y, this.z );
-
-	}
-
-};
-
-THREE.extend( THREE.Vector3.prototype, {
-
-	applyEuler: function () {
-
-		var q1 = new THREE.Quaternion();
-
-		return function ( v, eulerOrder ) {
-
-			var quaternion = q1.setFromEuler( v, eulerOrder );
-
-			this.applyQuaternion( quaternion );
-
-			return this;
-
-		};
-
-	}(),
-
-	applyAxisAngle: function () {
-
-		var q1 = new THREE.Quaternion();
-
-		return function ( axis, angle ) {
-
-			var quaternion = q1.setFromAxisAngle( axis, angle );
-
-			this.applyQuaternion( quaternion );
-
-			return this;
-
-		};
-
-	}(),
-
-	projectOnVector: function () {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( vector ) {
-
-			v1.copy( vector ).normalize();
-			var d = this.dot( v1 );
-			return this.copy( v1 ).multiplyScalar( d );
-
-		};
-
-	}(),
-
-	projectOnPlane: function () {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( planeNormal ) {
-
-			v1.copy( this ).projectOnVector( planeNormal );
-
-			return this.sub( v1 );
-
-		}
-
-	}(),
-
-	reflect: function () {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( vector ) {
-
-		    v1.copy( this ).projectOnVector( vector ).multiplyScalar( 2 );
-
-		    return this.subVectors( v1, this );
-
-		}
-
-	}()
-
-} );
-/**
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author philogb / http://blog.thejit.org/
- * @author mikael emtinger / http://gomo.se/
- * @author egraether / http://egraether.com/
- * @author WestLangley / http://github.com/WestLangley
- */
-
-THREE.Vector4 = function ( x, y, z, w ) {
-
-	this.x = x || 0;
-	this.y = y || 0;
-	this.z = z || 0;
-	this.w = ( w !== undefined ) ? w : 1;
-
-};
-
-THREE.Vector4.prototype = {
-
-	constructor: THREE.Vector4,
-
-	set: function ( x, y, z, w ) {
-
-		this.x = x;
-		this.y = y;
-		this.z = z;
-		this.w = w;
-
-		return this;
-
-	},
-
-	setX: function ( x ) {
-
-		this.x = x;
-
-		return this;
-
-	},
-
-	setY: function ( y ) {
-
-		this.y = y;
-
-		return this;
-
-	},
-
-	setZ: function ( z ) {
-
-		this.z = z;
-
-		return this;
-
-	},
-
-	setW: function ( w ) {
-
-		this.w = w;
-
-		return this;
-
-	},
-
-	setComponent: function ( index, value ) {
-
-		switch ( index ) {
-
-			case 0: this.x = value; break;
-			case 1: this.y = value; break;
-			case 2: this.z = value; break;
-			case 3: this.w = value; break;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	getComponent: function ( index ) {
-
-		switch ( index ) {
-
-			case 0: return this.x;
-			case 1: return this.y;
-			case 2: return this.z;
-			case 3: return this.w;
-			default: throw new Error( "index is out of range: " + index );
-
-		}
-
-	},
-
-	copy: function ( v ) {
-
-		this.x = v.x;
-		this.y = v.y;
-		this.z = v.z;
-		this.w = ( v.w !== undefined ) ? v.w : 1;
-
-		return this;
-
-	},
-
-	add: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
-			return this.addVectors( v, w );
-
-		}
-
-		this.x += v.x;
-		this.y += v.y;
-		this.z += v.z;
-		this.w += v.w;
-
-		return this;
-
-	},
-
-	addScalar: function ( s ) {
-
-		this.x += s;
-		this.y += s;
-		this.z += s;
-		this.w += s;
-
-		return this;
-
-	},
-
-	addVectors: function ( a, b ) {
-
-		this.x = a.x + b.x;
-		this.y = a.y + b.y;
-		this.z = a.z + b.z;
-		this.w = a.w + b.w;
-
-		return this;
-
-	},
-
-	sub: function ( v, w ) {
-
-		if ( w !== undefined ) {
-
-			console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
-			return this.subVectors( v, w );
-
-		}
-
-		this.x -= v.x;
-		this.y -= v.y;
-		this.z -= v.z;
-		this.w -= v.w;
-
-		return this;
-
-	},
-
-	subVectors: function ( a, b ) {
-
-		this.x = a.x - b.x;
-		this.y = a.y - b.y;
-		this.z = a.z - b.z;
-		this.w = a.w - b.w;
-
-		return this;
-
-	},
-
-	multiplyScalar: function ( s ) {
-
-		this.x *= s;
-		this.y *= s;
-		this.z *= s;
-		this.w *= s;
-
-		return this;
-
-	},
-
-	applyMatrix4: function ( m ) {
-
-		var x = this.x;
-		var y = this.y;
-		var z = this.z;
-		var w = this.w;
-
-		var e = m.elements;
-
-		this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w;
-		this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w;
-		this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w;
-		this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w;
-
-		return this;
-
-	},
-
-	divideScalar: function ( s ) {
-
-		if ( s !== 0 ) {
-
-			this.x /= s;
-			this.y /= s;
-			this.z /= s;
-			this.w /= s;
-
-		} else {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-			this.w = 1;
-
-		}
-
-		return this;
-
-	},
-
-	setAxisAngleFromQuaternion: function ( q ) {
-
-		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
-
-		// q is assumed to be normalized
-
-		this.w = 2 * Math.acos( q.w );
-
-		var s = Math.sqrt( 1 - q.w * q.w );
-
-		if ( s < 0.0001 ) {
-
-			 this.x = 1;
-			 this.y = 0;
-			 this.z = 0;
-
-		} else {
-
-			 this.x = q.x / s;
-			 this.y = q.y / s;
-			 this.z = q.z / s;
-
-		}
-
-		return this;
-
-	},
-
-	setAxisAngleFromRotationMatrix: function ( m ) {
-
-		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
-
-		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
-
-		var angle, x, y, z,		// variables for result
-			epsilon = 0.01,		// margin to allow for rounding errors
-			epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees
-
-			te = m.elements,
-
-			m11 = te[0], m12 = te[4], m13 = te[8],
-			m21 = te[1], m22 = te[5], m23 = te[9],
-			m31 = te[2], m32 = te[6], m33 = te[10];
-
-		if ( ( Math.abs( m12 - m21 ) < epsilon )
-		  && ( Math.abs( m13 - m31 ) < epsilon )
-		  && ( Math.abs( m23 - m32 ) < epsilon ) ) {
-
-			// singularity found
-			// first check for identity matrix which must have +1 for all terms
-			// in leading diagonal and zero in other terms
-
-			if ( ( Math.abs( m12 + m21 ) < epsilon2 )
-			  && ( Math.abs( m13 + m31 ) < epsilon2 )
-			  && ( Math.abs( m23 + m32 ) < epsilon2 )
-			  && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
-
-				// this singularity is identity matrix so angle = 0
-
-				this.set( 1, 0, 0, 0 );
-
-				return this; // zero angle, arbitrary axis
-
-			}
-
-			// otherwise this singularity is angle = 180
-
-			angle = Math.PI;
-
-			var xx = ( m11 + 1 ) / 2;
-			var yy = ( m22 + 1 ) / 2;
-			var zz = ( m33 + 1 ) / 2;
-			var xy = ( m12 + m21 ) / 4;
-			var xz = ( m13 + m31 ) / 4;
-			var yz = ( m23 + m32 ) / 4;
-
-			if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term
-
-				if ( xx < epsilon ) {
-
-					x = 0;
-					y = 0.707106781;
-					z = 0.707106781;
-
-				} else {
-
-					x = Math.sqrt( xx );
-					y = xy / x;
-					z = xz / x;
-
-				}
-
-			} else if ( yy > zz ) { // m22 is the largest diagonal term
-
-				if ( yy < epsilon ) {
-
-					x = 0.707106781;
-					y = 0;
-					z = 0.707106781;
-
-				} else {
-
-					y = Math.sqrt( yy );
-					x = xy / y;
-					z = yz / y;
-
-				}
-
-			} else { // m33 is the largest diagonal term so base result on this
-
-				if ( zz < epsilon ) {
-
-					x = 0.707106781;
-					y = 0.707106781;
-					z = 0;
-
-				} else {
-
-					z = Math.sqrt( zz );
-					x = xz / z;
-					y = yz / z;
-
-				}
-
-			}
-
-			this.set( x, y, z, angle );
-
-			return this; // return 180 deg rotation
-
-		}
-
-		// as we have reached here there are no singularities so we can handle normally
-
-		var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 )
-						 + ( m13 - m31 ) * ( m13 - m31 )
-						 + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
-
-		if ( Math.abs( s ) < 0.001 ) s = 1;
-
-		// prevent divide by zero, should not happen if matrix is orthogonal and should be
-		// caught by singularity test above, but I've left it in just in case
-
-		this.x = ( m32 - m23 ) / s;
-		this.y = ( m13 - m31 ) / s;
-		this.z = ( m21 - m12 ) / s;
-		this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
-
-		return this;
-
-	},
-
-	min: function ( v ) {
-
-		if ( this.x > v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y > v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		if ( this.z > v.z ) {
-
-			this.z = v.z;
-
-		}
-
-		if ( this.w > v.w ) {
-
-			this.w = v.w;
-
-		}
-
-		return this;
-
-	},
-
-	max: function ( v ) {
-
-		if ( this.x < v.x ) {
-
-			this.x = v.x;
-
-		}
-
-		if ( this.y < v.y ) {
-
-			this.y = v.y;
-
-		}
-
-		if ( this.z < v.z ) {
-
-			this.z = v.z;
-
-		}
-
-		if ( this.w < v.w ) {
-
-			this.w = v.w;
-
-		}
-
-		return this;
-
-	},
-
-	clamp: function ( min, max ) {
-
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
-
-		if ( this.x < min.x ) {
-
-			this.x = min.x;
-
-		} else if ( this.x > max.x ) {
-
-			this.x = max.x;
-
-		}
-
-		if ( this.y < min.y ) {
-
-			this.y = min.y;
-
-		} else if ( this.y > max.y ) {
-
-			this.y = max.y;
-
-		}
-
-		if ( this.z < min.z ) {
-
-			this.z = min.z;
-
-		} else if ( this.z > max.z ) {
-
-			this.z = max.z;
-
-		}
-
-		if ( this.w < min.w ) {
-
-			this.w = min.w;
-
-		} else if ( this.w > max.w ) {
-
-			this.w = max.w;
-
-		}
-
-		return this;
-
-	},
-
-	negate: function() {
-
-		return this.multiplyScalar( -1 );
-
-	},
-
-	dot: function ( v ) {
-
-		return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
-
-	},
-
-	lengthSq: function () {
-
-		return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
-
-	},
-
-	length: function () {
-
-		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
-
-	},
-
-	lengthManhattan: function () {
-
-		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
-
-	},
-
-	normalize: function () {
-
-		return this.divideScalar( this.length() );
-
-	},
-
-	setLength: function ( l ) {
-
-		var oldLength = this.length();
-
-		if ( oldLength !== 0 && l !== oldLength ) {
-
-			this.multiplyScalar( l / oldLength );
-		}
-
-		return this;
-
-	},
-
-	lerp: function ( v, alpha ) {
-
-		this.x += ( v.x - this.x ) * alpha;
-		this.y += ( v.y - this.y ) * alpha;
-		this.z += ( v.z - this.z ) * alpha;
-		this.w += ( v.w - this.w ) * alpha;
-
-		return this;
-
-	},
-
-	equals: function ( v ) {
-
-		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
-
-	},
-
-	fromArray: function ( array ) {
-
-		this.x = array[ 0 ];
-		this.y = array[ 1 ];
-		this.z = array[ 2 ];
-		this.w = array[ 3 ];
-
-		return this;
-
-	},
-
-	toArray: function () {
-
-		return [ this.x, this.y, this.z, this.w ];
-
-	},
-
-	clone: function () {
-
-		return new THREE.Vector4( this.x, this.y, this.z, this.w );
-
-	}
-
-};
-/**
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Line3 = function ( start, end ) {
-
-	this.start = ( start !== undefined ) ? start : new THREE.Vector3();
-	this.end = ( end !== undefined ) ? end : new THREE.Vector3();
-
-};
-
-THREE.Line3.prototype = {
-
-	constructor: THREE.Line3,
-
-	set: function ( start, end ) {
-
-		this.start.copy( start );
-		this.end.copy( end );
-
-		return this;
-
-	},
-
-	copy: function ( line ) {
-
-		this.start.copy( line.start );
-		this.end.copy( line.end );
-
-		return this;
-
-	},
-
-	center: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
-
-	},
-
-	delta: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.subVectors( this.end, this.start );
-
-	},
-
-	distanceSq: function () {
-
-		return this.start.distanceToSquared( this.end );
-
-	},
-
-	distance: function () {
-
-		return this.start.distanceTo( this.end );
-
-	},
-
-	at: function ( t, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-
-		return this.delta( result ).multiplyScalar( t ).add( this.start );
-
-	},
-
-	closestPointToPointParameter: function() {
-
-		var startP = new THREE.Vector3();
-		var startEnd = new THREE.Vector3();
-
-		return function ( point, clampToLine ) {
-
-			startP.subVectors( point, this.start );
-			startEnd.subVectors( this.end, this.start );
-
-			var startEnd2 = startEnd.dot( startEnd );
-			var startEnd_startP = startEnd.dot( startP );
-
-			var t = startEnd_startP / startEnd2;
-
-			if ( clampToLine ) {
-
-				t = THREE.Math.clamp( t, 0, 1 );
-
-			}
-
-			return t;
-
-		};
-
-	}(),
-
-	closestPointToPoint: function ( point, clampToLine, optionalTarget ) {
-
-		var t = this.closestPointToPointParameter( point, clampToLine );
-
-		var result = optionalTarget || new THREE.Vector3();
-
-		return this.delta( result ).multiplyScalar( t ).add( this.start );
-
-	},
-
-	applyMatrix4: function ( matrix ) {
-
-		this.start.applyMatrix4( matrix );
-		this.end.applyMatrix4( matrix );
-
-		return this;
-
-	},
-
-	equals: function ( line ) {
-
-		return line.start.equals( this.start ) && line.end.equals( this.end );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Line3().copy( this );
-
-	}
-
-};
-/**
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Box2 = function ( min, max ) {
-
-	this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity );
-	this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity );
-
-};
-
-THREE.Box2.prototype = {
-
-	constructor: THREE.Box2,
-
-	set: function ( min, max ) {
-
-		this.min.copy( min );
-		this.max.copy( max );
-
-		return this;
-
-	},
-
-	setFromPoints: function ( points ) {
-
-		if ( points.length > 0 ) {
-
-			var point = points[ 0 ];
-
-			this.min.copy( point );
-			this.max.copy( point );
-
-			for ( var i = 1, il = points.length; i < il; i ++ ) {
-
-				point = points[ i ];
-
-				if ( point.x < this.min.x ) {
-
-					this.min.x = point.x;
-
-				} else if ( point.x > this.max.x ) {
-
-					this.max.x = point.x;
-
-				}
-
-				if ( point.y < this.min.y ) {
-
-					this.min.y = point.y;
-
-				} else if ( point.y > this.max.y ) {
-
-					this.max.y = point.y;
-
-				}
-
-			}
-
-		} else {
-
-			this.makeEmpty();
-
-		}
-
-		return this;
-
-	},
-
-	setFromCenterAndSize: function () {
-
-		var v1 = new THREE.Vector2();
-
-		return function ( center, size ) {
-
-			var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
-			this.min.copy( center ).sub( halfSize );
-			this.max.copy( center ).add( halfSize );
-
-			return this;
-
-		};
-
-	}(),
-
-	copy: function ( box ) {
-
-		this.min.copy( box.min );
-		this.max.copy( box.max );
-
-		return this;
-
-	},
-
-	makeEmpty: function () {
-
-		this.min.x = this.min.y = Infinity;
-		this.max.x = this.max.y = -Infinity;
-
-		return this;
-
-	},
-
-	empty: function () {
-
-		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
-
-		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
-
-	},
-
-	center: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector2();
-		return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
-
-	},
-
-	size: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector2();
-		return result.subVectors( this.max, this.min );
-
-	},
-
-	expandByPoint: function ( point ) {
-
-		this.min.min( point );
-		this.max.max( point );
-
-		return this;
-	},
-
-	expandByVector: function ( vector ) {
-
-		this.min.sub( vector );
-		this.max.add( vector );
-
-		return this;
-	},
-
-	expandByScalar: function ( scalar ) {
-
-		this.min.addScalar( -scalar );
-		this.max.addScalar( scalar );
-
-		return this;
-	},
-
-	containsPoint: function ( point ) {
-
-		if ( point.x < this.min.x || point.x > this.max.x ||
-		     point.y < this.min.y || point.y > this.max.y ) {
-
-			return false;
-
-		}
-
-		return true;
-
-	},
-
-	containsBox: function ( box ) {
-
-		if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
-		     ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) {
-
-			return true;
-
-		}
-
-		return false;
-
-	},
-
-	getParameter: function ( point ) {
-
-		// This can potentially have a divide by zero if the box
-		// has a size dimension of 0.
-
-		return new THREE.Vector2(
-			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
-			( point.y - this.min.y ) / ( this.max.y - this.min.y )
-		);
-
-	},
-
-	isIntersectionBox: function ( box ) {
-
-		// using 6 splitting planes to rule out intersections.
-
-		if ( box.max.x < this.min.x || box.min.x > this.max.x ||
-		     box.max.y < this.min.y || box.min.y > this.max.y ) {
-
-			return false;
-
-		}
-
-		return true;
-
-	},
-
-	clampPoint: function ( point, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector2();
-		return result.copy( point ).clamp( this.min, this.max );
-
-	},
-
-	distanceToPoint: function () {
-
-		var v1 = new THREE.Vector2();
-
-		return function ( point ) {
-
-			var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
-			return clampedPoint.sub( point ).length();
-
-		};
-
-	}(),
-
-	intersect: function ( box ) {
-
-		this.min.max( box.min );
-		this.max.min( box.max );
-
-		return this;
-
-	},
-
-	union: function ( box ) {
-
-		this.min.min( box.min );
-		this.max.max( box.max );
-
-		return this;
-
-	},
-
-	translate: function ( offset ) {
-
-		this.min.add( offset );
-		this.max.add( offset );
-
-		return this;
-
-	},
-
-	equals: function ( box ) {
-
-		return box.min.equals( this.min ) && box.max.equals( this.max );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Box2().copy( this );
-
-	}
-
-};
-/**
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Box3 = function ( min, max ) {
-
-	this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity );
-	this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity );
-
-};
-
-THREE.Box3.prototype = {
-
-	constructor: THREE.Box3,
-
-	set: function ( min, max ) {
-
-		this.min.copy( min );
-		this.max.copy( max );
-
-		return this;
-
-	},
-
-	setFromPoints: function ( points ) {
-
-		if ( points.length > 0 ) {
-
-			var point = points[ 0 ];
-
-			this.min.copy( point );
-			this.max.copy( point );
-
-			for ( var i = 1, il = points.length; i < il; i ++ ) {
-
-				point = points[ i ];
-
-				if ( point.x < this.min.x ) {
-
-					this.min.x = point.x;
-
-				} else if ( point.x > this.max.x ) {
-
-					this.max.x = point.x;
-
-				}
-
-				if ( point.y < this.min.y ) {
-
-					this.min.y = point.y;
-
-				} else if ( point.y > this.max.y ) {
-
-					this.max.y = point.y;
-
-				}
-
-				if ( point.z < this.min.z ) {
-
-					this.min.z = point.z;
-
-				} else if ( point.z > this.max.z ) {
-
-					this.max.z = point.z;
-
-				}
-
-			}
-
-		} else {
-
-			this.makeEmpty();
-
-		}
-
-		return this;
-
-	},
-
-	setFromCenterAndSize: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( center, size ) {
-
-			var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
-
-			this.min.copy( center ).sub( halfSize );
-			this.max.copy( center ).add( halfSize );
-
-			return this;
-
-		};
-
-	}(),
-
-	copy: function ( box ) {
-
-		this.min.copy( box.min );
-		this.max.copy( box.max );
-
-		return this;
-
-	},
-
-	makeEmpty: function () {
-
-		this.min.x = this.min.y = this.min.z = Infinity;
-		this.max.x = this.max.y = this.max.z = -Infinity;
-
-		return this;
-
-	},
-
-	empty: function () {
-
-		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
-
-		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
-
-	},
-
-	center: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
-
-	},
-
-	size: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.subVectors( this.max, this.min );
-
-	},
-
-	expandByPoint: function ( point ) {
-
-		this.min.min( point );
-		this.max.max( point );
-
-		return this;
-
-	},
-
-	expandByVector: function ( vector ) {
-
-		this.min.sub( vector );
-		this.max.add( vector );
-
-		return this;
-
-	},
-
-	expandByScalar: function ( scalar ) {
-
-		this.min.addScalar( -scalar );
-		this.max.addScalar( scalar );
-
-		return this;
-
-	},
-
-	containsPoint: function ( point ) {
-
-		if ( point.x < this.min.x || point.x > this.max.x ||
-		     point.y < this.min.y || point.y > this.max.y ||
-		     point.z < this.min.z || point.z > this.max.z ) {
-
-			return false;
-
-		}
-
-		return true;
-
-	},
-
-	containsBox: function ( box ) {
-
-		if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
-			 ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) &&
-			 ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) {
-
-			return true;
-
-		}
-
-		return false;
-
-	},
-
-	getParameter: function ( point ) {
-
-		// This can potentially have a divide by zero if the box
-		// has a size dimension of 0.
-
-		return new THREE.Vector3(
-			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
-			( point.y - this.min.y ) / ( this.max.y - this.min.y ),
-			( point.z - this.min.z ) / ( this.max.z - this.min.z )
-		);
-
-	},
-
-	isIntersectionBox: function ( box ) {
-
-		// using 6 splitting planes to rule out intersections.
-
-		if ( box.max.x < this.min.x || box.min.x > this.max.x ||
-		     box.max.y < this.min.y || box.min.y > this.max.y ||
-		     box.max.z < this.min.z || box.min.z > this.max.z ) {
-
-			return false;
-
-		}
-
-		return true;
-
-	},
-
-	clampPoint: function ( point, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.copy( point ).clamp( this.min, this.max );
-
-	},
-
-	distanceToPoint: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( point ) {
-
-			var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
-			return clampedPoint.sub( point ).length();
-
-		};
-
-	}(),
-
-	getBoundingSphere: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( optionalTarget ) {
-
-			var result = optionalTarget || new THREE.Sphere();
-
-			result.center = this.center();
-			result.radius = this.size( v1 ).length() * 0.5;
-
-			return result;
-
-		};
-
-	}(),
-
-	intersect: function ( box ) {
-
-		this.min.max( box.min );
-		this.max.min( box.max );
-
-		return this;
-
-	},
-
-	union: function ( box ) {
-
-		this.min.min( box.min );
-		this.max.max( box.max );
-
-		return this;
-
-	},
-
-	applyMatrix4: function() {
-
-		var points = [
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3(),
-			new THREE.Vector3()
-		];
-
-		return function ( matrix ) {
-
-			// NOTE: I am using a binary pattern to specify all 2^3 combinations below
-			points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
-			points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
-			points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
-			points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
-			points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
-			points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
-			points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
-			points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );  // 111
-
-			this.makeEmpty();
-			this.setFromPoints( points );
-
-			return this;
-
-		};
-
-	}(),
-
-	translate: function ( offset ) {
-
-		this.min.add( offset );
-		this.max.add( offset );
-
-		return this;
-
-	},
-
-	equals: function ( box ) {
-
-		return box.min.equals( this.min ) && box.max.equals( this.max );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Box3().copy( this );
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author WestLangley / http://github.com/WestLangley
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
-
-	this.elements = new Float32Array(9);
-
-	this.set(
-
-		( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0,
-		n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0,
-		n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1
-
-	);
-};
-
-THREE.Matrix3.prototype = {
-
-	constructor: THREE.Matrix3,
-
-	set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
-
-		var te = this.elements;
-
-		te[0] = n11; te[3] = n12; te[6] = n13;
-		te[1] = n21; te[4] = n22; te[7] = n23;
-		te[2] = n31; te[5] = n32; te[8] = n33;
-
-		return this;
-
-	},
-
-	identity: function () {
-
-		this.set(
-
-			1, 0, 0,
-			0, 1, 0,
-			0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	copy: function ( m ) {
-
-		var me = m.elements;
-
-		this.set(
-
-			me[0], me[3], me[6],
-			me[1], me[4], me[7],
-			me[2], me[5], me[8]
-
-		);
-
-		return this;
-
-	},
-
-	multiplyVector3: function ( vector ) {
-
-		console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
-		return vector.applyMatrix3( this );
-
-	},
-
-	multiplyVector3Array: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( a ) {
-
-			for ( var i = 0, il = a.length; i < il; i += 3 ) {
-
-				v1.x = a[ i ];
-				v1.y = a[ i + 1 ];
-				v1.z = a[ i + 2 ];
-
-				v1.applyMatrix3(this);
-
-				a[ i ]     = v1.x;
-				a[ i + 1 ] = v1.y;
-				a[ i + 2 ] = v1.z;
-
-			}
-
-			return a;
-
-		};
-
-	}(),
-
-	multiplyScalar: function ( s ) {
-
-		var te = this.elements;
-
-		te[0] *= s; te[3] *= s; te[6] *= s;
-		te[1] *= s; te[4] *= s; te[7] *= s;
-		te[2] *= s; te[5] *= s; te[8] *= s;
-
-		return this;
-
-	},
-
-	determinant: function () {
-
-		var te = this.elements;
-
-		var a = te[0], b = te[1], c = te[2],
-			d = te[3], e = te[4], f = te[5],
-			g = te[6], h = te[7], i = te[8];
-
-		return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g;
-
-	},
-
-	getInverse: function ( matrix, throwOnInvertible ) {
-
-		// input: THREE.Matrix4
-		// ( based on http://code.google.com/p/webgl-mjs/ )
-
-		var me = matrix.elements;
-		var te = this.elements;
-
-		te[ 0 ] =   me[10] * me[5] - me[6] * me[9];
-		te[ 1 ] = - me[10] * me[1] + me[2] * me[9];
-		te[ 2 ] =   me[6] * me[1] - me[2] * me[5];
-		te[ 3 ] = - me[10] * me[4] + me[6] * me[8];
-		te[ 4 ] =   me[10] * me[0] - me[2] * me[8];
-		te[ 5 ] = - me[6] * me[0] + me[2] * me[4];
-		te[ 6 ] =   me[9] * me[4] - me[5] * me[8];
-		te[ 7 ] = - me[9] * me[0] + me[1] * me[8];
-		te[ 8 ] =   me[5] * me[0] - me[1] * me[4];
-
-		var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ];
-
-		// no inverse
-
-		if ( det === 0 ) {
-
-			var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0";
-
-			if ( throwOnInvertible || false ) {
-
-				throw new Error( msg ); 
-
-			} else {
-
-				console.warn( msg );
-
-			}
-
-			this.identity();
-
-			return this;
-
-		}
-
-		this.multiplyScalar( 1.0 / det );
-
-		return this;
-
-	},
-
-	transpose: function () {
-
-		var tmp, m = this.elements;
-
-		tmp = m[1]; m[1] = m[3]; m[3] = tmp;
-		tmp = m[2]; m[2] = m[6]; m[6] = tmp;
-		tmp = m[5]; m[5] = m[7]; m[7] = tmp;
-
-		return this;
-
-	},
-
-	getNormalMatrix: function ( m ) {
-
-		// input: THREE.Matrix4
-
-		this.getInverse( m ).transpose();
-
-		return this;
-
-	},
-
-	transposeIntoArray: function ( r ) {
-
-		var m = this.elements;
-
-		r[ 0 ] = m[ 0 ];
-		r[ 1 ] = m[ 3 ];
-		r[ 2 ] = m[ 6 ];
-		r[ 3 ] = m[ 1 ];
-		r[ 4 ] = m[ 4 ];
-		r[ 5 ] = m[ 7 ];
-		r[ 6 ] = m[ 2 ];
-		r[ 7 ] = m[ 5 ];
-		r[ 8 ] = m[ 8 ];
-
-		return this;
-
-	},
-
-	clone: function () {
-
-		var te = this.elements;
-
-		return new THREE.Matrix3(
-
-			te[0], te[3], te[6],
-			te[1], te[4], te[7],
-			te[2], te[5], te[8]
-
-		);
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author philogb / http://blog.thejit.org/
- * @author jordi_ros / http://plattsoft.com
- * @author D1plo1d / http://github.com/D1plo1d
- * @author alteredq / http://alteredqualia.com/
- * @author mikael emtinger / http://gomo.se/
- * @author timknip / http://www.floorplanner.com/
- * @author bhouston / http://exocortex.com
- * @author WestLangley / http://github.com/WestLangley
- */
-
-
-THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
-
-	var te = this.elements = new Float32Array( 16 );
-
-	// TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix
-	//   we should not support semi specification of Matrix4, it is just weird.
-
-	te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0;
-	te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0;
-	te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0;
-	te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1;
-
-};
-
-THREE.Matrix4.prototype = {
-
-	constructor: THREE.Matrix4,
-
-	set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
-
-		var te = this.elements;
-
-		te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
-		te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
-		te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
-		te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;
-
-		return this;
-
-	},
-
-	identity: function () {
-
-		this.set(
-
-			1, 0, 0, 0,
-			0, 1, 0, 0,
-			0, 0, 1, 0,
-			0, 0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	copy: function ( m ) {
-
-		var me = m.elements;
-
-		this.set(
-
-			me[0], me[4], me[8], me[12],
-			me[1], me[5], me[9], me[13],
-			me[2], me[6], me[10], me[14],
-			me[3], me[7], me[11], me[15]
-
-		);
-
-		return this;
-
-	},
-
-	extractPosition: function ( m ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' );
-		return this.copyPosition( m );
-
-	},
-
-	copyPosition: function ( m ) {
-
-		var te = this.elements;
-		var me = m.elements;
-
-		te[12] = me[12];
-		te[13] = me[13];
-		te[14] = me[14];
-
-		return this;
-
-	},
-
-	extractRotation: function () {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( m ) {
-
-			var te = this.elements;
-			var me = m.elements;
-
-			var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length();
-			var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length();
-			var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length();
-
-			te[0] = me[0] * scaleX;
-			te[1] = me[1] * scaleX;
-			te[2] = me[2] * scaleX;
-
-			te[4] = me[4] * scaleY;
-			te[5] = me[5] * scaleY;
-			te[6] = me[6] * scaleY;
-
-			te[8] = me[8] * scaleZ;
-			te[9] = me[9] * scaleZ;
-			te[10] = me[10] * scaleZ;
-
-			return this;
-
-		};
-
-	}(),
-
-	setRotationFromEuler: function ( v, order ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromEuler() has been deprecated in favor of makeRotationFromEuler.  Please update your code.' );
-
-		return this.makeRotationFromEuler( v, order );
-
-	},
-
-	makeRotationFromEuler: function ( v, order ) {
-
-		var te = this.elements;
-
-		var x = v.x, y = v.y, z = v.z;
-		var a = Math.cos( x ), b = Math.sin( x );
-		var c = Math.cos( y ), d = Math.sin( y );
-		var e = Math.cos( z ), f = Math.sin( z );
-
-		if ( order === undefined || order === 'XYZ' ) {
-
-			var ae = a * e, af = a * f, be = b * e, bf = b * f;
-
-			te[0] = c * e;
-			te[4] = - c * f;
-			te[8] = d;
-
-			te[1] = af + be * d;
-			te[5] = ae - bf * d;
-			te[9] = - b * c;
-
-			te[2] = bf - ae * d;
-			te[6] = be + af * d;
-			te[10] = a * c;
-
-		} else if ( order === 'YXZ' ) {
-
-			var ce = c * e, cf = c * f, de = d * e, df = d * f;
-
-			te[0] = ce + df * b;
-			te[4] = de * b - cf;
-			te[8] = a * d;
-
-			te[1] = a * f;
-			te[5] = a * e;
-			te[9] = - b;
-
-			te[2] = cf * b - de;
-			te[6] = df + ce * b;
-			te[10] = a * c;
-
-		} else if ( order === 'ZXY' ) {
-
-			var ce = c * e, cf = c * f, de = d * e, df = d * f;
-
-			te[0] = ce - df * b;
-			te[4] = - a * f;
-			te[8] = de + cf * b;
-
-			te[1] = cf + de * b;
-			te[5] = a * e;
-			te[9] = df - ce * b;
-
-			te[2] = - a * d;
-			te[6] = b;
-			te[10] = a * c;
-
-		} else if ( order === 'ZYX' ) {
-
-			var ae = a * e, af = a * f, be = b * e, bf = b * f;
-
-			te[0] = c * e;
-			te[4] = be * d - af;
-			te[8] = ae * d + bf;
-
-			te[1] = c * f;
-			te[5] = bf * d + ae;
-			te[9] = af * d - be;
-
-			te[2] = - d;
-			te[6] = b * c;
-			te[10] = a * c;
-
-		} else if ( order === 'YZX' ) {
-
-			var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
-
-			te[0] = c * e;
-			te[4] = bd - ac * f;
-			te[8] = bc * f + ad;
-
-			te[1] = f;
-			te[5] = a * e;
-			te[9] = - b * e;
-
-			te[2] = - d * e;
-			te[6] = ad * f + bc;
-			te[10] = ac - bd * f;
-
-		} else if ( order === 'XZY' ) {
-
-			var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
-
-			te[0] = c * e;
-			te[4] = - f;
-			te[8] = d * e;
-
-			te[1] = ac * f + bd;
-			te[5] = a * e;
-			te[9] = ad * f - bc;
-
-			te[2] = bc * f - ad;
-			te[6] = b * e;
-			te[10] = bd * f + ac;
-
-		}
-
-		// last column
-		te[3] = 0;
-		te[7] = 0;
-		te[11] = 0;
-
-		// bottom row
-		te[12] = 0;
-		te[13] = 0;
-		te[14] = 0;
-		te[15] = 1;
-
-		return this;
-
-	},
-
-	setRotationFromQuaternion: function ( q ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion.  Please update your code.' );
-
-		return this.makeRotationFromQuaternion( q );
-
-	},
-
-	makeRotationFromQuaternion: function ( q ) {
-
-		var te = this.elements;
-
-		var x = q.x, y = q.y, z = q.z, w = q.w;
-		var x2 = x + x, y2 = y + y, z2 = z + z;
-		var xx = x * x2, xy = x * y2, xz = x * z2;
-		var yy = y * y2, yz = y * z2, zz = z * z2;
-		var wx = w * x2, wy = w * y2, wz = w * z2;
-
-		te[0] = 1 - ( yy + zz );
-		te[4] = xy - wz;
-		te[8] = xz + wy;
-
-		te[1] = xy + wz;
-		te[5] = 1 - ( xx + zz );
-		te[9] = yz - wx;
-
-		te[2] = xz - wy;
-		te[6] = yz + wx;
-		te[10] = 1 - ( xx + yy );
-
-		// last column
-		te[3] = 0;
-		te[7] = 0;
-		te[11] = 0;
-
-		// bottom row
-		te[12] = 0;
-		te[13] = 0;
-		te[14] = 0;
-		te[15] = 1;
-
-		return this;
-
-	},
-
-	lookAt: function() {
-
-		var x = new THREE.Vector3();
-		var y = new THREE.Vector3();
-		var z = new THREE.Vector3();
-
-		return function ( eye, target, up ) {
-
-			var te = this.elements;
-
-			z.subVectors( eye, target ).normalize();
-
-			if ( z.length() === 0 ) {
-
-				z.z = 1;
-
-			}
-
-			x.crossVectors( up, z ).normalize();
-
-			if ( x.length() === 0 ) {
-
-				z.x += 0.0001;
-				x.crossVectors( up, z ).normalize();
-
-			}
-
-			y.crossVectors( z, x );
-
-
-			te[0] = x.x; te[4] = y.x; te[8] = z.x;
-			te[1] = x.y; te[5] = y.y; te[9] = z.y;
-			te[2] = x.z; te[6] = y.z; te[10] = z.z;
-
-			return this;
-
-		};
-
-	}(),
-
-	multiply: function ( m, n ) {
-
-		if ( n !== undefined ) {
-
-			console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
-			return this.multiplyMatrices( m, n );
-
-		}
-
-		return this.multiplyMatrices( this, m );
-
-	},
-
-	multiplyMatrices: function ( a, b ) {
-
-		var ae = a.elements;
-		var be = b.elements;
-		var te = this.elements;
-
-		var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
-		var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
-		var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
-		var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
-
-		var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12];
-		var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13];
-		var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14];
-		var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15];
-
-		te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
-		te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
-		te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
-		te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
-
-		te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
-		te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
-		te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
-		te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
-
-		te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
-		te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
-		te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
-		te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
-
-		te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
-		te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
-		te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
-		te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
-
-		return this;
-
-	},
-
-	multiplyToArray: function ( a, b, r ) {
-
-		var te = this.elements;
-
-		this.multiplyMatrices( a, b );
-
-		r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3];
-		r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7];
-		r[ 8 ]  = te[8]; r[ 9 ]  = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11];
-		r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15];
-
-		return this;
-
-	},
-
-	multiplyScalar: function ( s ) {
-
-		var te = this.elements;
-
-		te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s;
-		te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s;
-		te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s;
-		te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s;
-
-		return this;
-
-	},
-
-	multiplyVector3: function ( vector ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' );
-		return vector.applyProjection( this );
-
-	},
-
-	multiplyVector4: function ( vector ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
-		return vector.applyMatrix4( this );
-
-	},
-
-	multiplyVector3Array: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( a ) {
-
-			for ( var i = 0, il = a.length; i < il; i += 3 ) {
-
-				v1.x = a[ i ];
-				v1.y = a[ i + 1 ];
-				v1.z = a[ i + 2 ];
-
-				v1.applyProjection( this );
-
-				a[ i ]     = v1.x;
-				a[ i + 1 ] = v1.y;
-				a[ i + 2 ] = v1.z;
-
-			}
-
-			return a;
-
-		};
-
-	}(),
-
-	rotateAxis: function ( v ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
-
-		v.transformDirection( this );
-
-	},
-
-	crossVector: function ( vector ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
-		return vector.applyMatrix4( this );
-
-	},
-
-	determinant: function () {
-
-		var te = this.elements;
-
-		var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12];
-		var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13];
-		var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14];
-		var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15];
-
-		//TODO: make this more efficient
-		//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
-
-		return (
-			n41 * (
-				+n14 * n23 * n32
-				-n13 * n24 * n32
-				-n14 * n22 * n33
-				+n12 * n24 * n33
-				+n13 * n22 * n34
-				-n12 * n23 * n34
-			) +
-			n42 * (
-				+n11 * n23 * n34
-				-n11 * n24 * n33
-				+n14 * n21 * n33
-				-n13 * n21 * n34
-				+n13 * n24 * n31
-				-n14 * n23 * n31
-			) +
-			n43 * (
-				+n11 * n24 * n32
-				-n11 * n22 * n34
-				-n14 * n21 * n32
-				+n12 * n21 * n34
-				+n14 * n22 * n31
-				-n12 * n24 * n31
-			) +
-			n44 * (
-				-n13 * n22 * n31
-				-n11 * n23 * n32
-				+n11 * n22 * n33
-				+n13 * n21 * n32
-				-n12 * n21 * n33
-				+n12 * n23 * n31
-			)
-
-		);
-
-	},
-
-	transpose: function () {
-
-		var te = this.elements;
-		var tmp;
-
-		tmp = te[1]; te[1] = te[4]; te[4] = tmp;
-		tmp = te[2]; te[2] = te[8]; te[8] = tmp;
-		tmp = te[6]; te[6] = te[9]; te[9] = tmp;
-
-		tmp = te[3]; te[3] = te[12]; te[12] = tmp;
-		tmp = te[7]; te[7] = te[13]; te[13] = tmp;
-		tmp = te[11]; te[11] = te[14]; te[14] = tmp;
-
-		return this;
-
-	},
-
-	flattenToArray: function ( flat ) {
-
-		var te = this.elements;
-		flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3];
-		flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7];
-		flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11];
-		flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15];
-
-		return flat;
-
-	},
-
-	flattenToArrayOffset: function( flat, offset ) {
-
-		var te = this.elements;
-		flat[ offset ] = te[0];
-		flat[ offset + 1 ] = te[1];
-		flat[ offset + 2 ] = te[2];
-		flat[ offset + 3 ] = te[3];
-
-		flat[ offset + 4 ] = te[4];
-		flat[ offset + 5 ] = te[5];
-		flat[ offset + 6 ] = te[6];
-		flat[ offset + 7 ] = te[7];
-
-		flat[ offset + 8 ]  = te[8];
-		flat[ offset + 9 ]  = te[9];
-		flat[ offset + 10 ] = te[10];
-		flat[ offset + 11 ] = te[11];
-
-		flat[ offset + 12 ] = te[12];
-		flat[ offset + 13 ] = te[13];
-		flat[ offset + 14 ] = te[14];
-		flat[ offset + 15 ] = te[15];
-
-		return flat;
-
-	},
-
-	getPosition: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function () {
-
-			console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead.' );
-
-			var te = this.elements;
-			return v1.set( te[12], te[13], te[14] );
-
-		};
-
-	}(),
-
-	setPosition: function ( v ) {
-
-		var te = this.elements;
-
-		te[12] = v.x;
-		te[13] = v.y;
-		te[14] = v.z;
-
-		return this;
-
-	},
-
-	getInverse: function ( m, throwOnInvertible ) {
-
-		// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
-		var te = this.elements;
-		var me = m.elements;
-
-		var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12];
-		var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13];
-		var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14];
-		var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15];
-
-		te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44;
-		te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44;
-		te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44;
-		te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34;
-		te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44;
-		te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44;
-		te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44;
-		te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34;
-		te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44;
-		te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44;
-		te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44;
-		te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34;
-		te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43;
-		te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43;
-		te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43;
-		te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33;
-
-		var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 4 ] + me[ 2 ] * te[ 8 ] + me[ 3 ] * te[ 12 ];
-
-		if ( det == 0 ) {
-
-			var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0";
-
-			if ( throwOnInvertible || false ) {
-
-				throw new Error( msg ); 
-
-			} else {
-
-				console.warn( msg );
-
-			}
-
-			this.identity();
-
-			return this;
-		}
-
-		this.multiplyScalar( 1 / det );
-
-		return this;
-
-	},
-
-	translate: function ( v ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.');
-
-	},
-
-	rotateX: function ( angle ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.');
-
-	},
-
-	rotateY: function ( angle ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.');
-
-	},
-
-	rotateZ: function ( angle ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.');
-
-	},
-
-	rotateByAxis: function ( axis, angle ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.');
-
-	},
-
-	scale: function ( v ) {
-
-		var te = this.elements;
-		var x = v.x, y = v.y, z = v.z;
-
-		te[0] *= x; te[4] *= y; te[8] *= z;
-		te[1] *= x; te[5] *= y; te[9] *= z;
-		te[2] *= x; te[6] *= y; te[10] *= z;
-		te[3] *= x; te[7] *= y; te[11] *= z;
-
-		return this;
-
-	},
-
-	getMaxScaleOnAxis: function () {
-
-		var te = this.elements;
-
-		var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
-		var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
-		var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
-
-		return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) );
-
-	},
-
-	makeTranslation: function ( x, y, z ) {
-
-		this.set(
-
-			1, 0, 0, x,
-			0, 1, 0, y,
-			0, 0, 1, z,
-			0, 0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	makeRotationX: function ( theta ) {
-
-		var c = Math.cos( theta ), s = Math.sin( theta );
-
-		this.set(
-
-			1, 0,  0, 0,
-			0, c, -s, 0,
-			0, s,  c, 0,
-			0, 0,  0, 1
-
-		);
-
-		return this;
-
-	},
-
-	makeRotationY: function ( theta ) {
-
-		var c = Math.cos( theta ), s = Math.sin( theta );
-
-		this.set(
-
-			 c, 0, s, 0,
-			 0, 1, 0, 0,
-			-s, 0, c, 0,
-			 0, 0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	makeRotationZ: function ( theta ) {
-
-		var c = Math.cos( theta ), s = Math.sin( theta );
-
-		this.set(
-
-			c, -s, 0, 0,
-			s,  c, 0, 0,
-			0,  0, 1, 0,
-			0,  0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	makeRotationAxis: function ( axis, angle ) {
-
-		// Based on http://www.gamedev.net/reference/articles/article1199.asp
-
-		var c = Math.cos( angle );
-		var s = Math.sin( angle );
-		var t = 1 - c;
-		var x = axis.x, y = axis.y, z = axis.z;
-		var tx = t * x, ty = t * y;
-
-		this.set(
-
-			tx * x + c, tx * y - s * z, tx * z + s * y, 0,
-			tx * y + s * z, ty * y + c, ty * z - s * x, 0,
-			tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
-			0, 0, 0, 1
-
-		);
-
-		 return this;
-
-	},
-
-	makeScale: function ( x, y, z ) {
-
-		this.set(
-
-			x, 0, 0, 0,
-			0, y, 0, 0,
-			0, 0, z, 0,
-			0, 0, 0, 1
-
-		);
-
-		return this;
-
-	},
-
-	compose: function ( position, quaternion, scale ) {
-
-		console.warn( 'DEPRECATED: Matrix4\'s .compose() has been deprecated in favor of makeFromPositionQuaternionScale. Please update your code.' );
-
-		return this.makeFromPositionQuaternionScale( position, quaternion, scale );
-
-	},
-
-	makeFromPositionQuaternionScale: function ( position, quaternion, scale ) {
-
-		this.makeRotationFromQuaternion( quaternion );
-		this.scale( scale );
-		this.setPosition( position );
-
-		return this;
-
-	},
-
-	makeFromPositionEulerScale: function ( position, rotation, eulerOrder, scale ) {
-
-		this.makeRotationFromEuler( rotation, eulerOrder );
-		this.scale( scale );
-		this.setPosition( position );
-
-		return this;
-
-	},
-
-	makeFrustum: function ( left, right, bottom, top, near, far ) {
-
-		var te = this.elements;
-		var x = 2 * near / ( right - left );
-		var y = 2 * near / ( top - bottom );
-
-		var a = ( right + left ) / ( right - left );
-		var b = ( top + bottom ) / ( top - bottom );
-		var c = - ( far + near ) / ( far - near );
-		var d = - 2 * far * near / ( far - near );
-
-		te[0] = x;	te[4] = 0;	te[8] = a;	te[12] = 0;
-		te[1] = 0;	te[5] = y;	te[9] = b;	te[13] = 0;
-		te[2] = 0;	te[6] = 0;	te[10] = c;	te[14] = d;
-		te[3] = 0;	te[7] = 0;	te[11] = - 1;	te[15] = 0;
-
-		return this;
-
-	},
-
-	makePerspective: function ( fov, aspect, near, far ) {
-
-		var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) );
-		var ymin = - ymax;
-		var xmin = ymin * aspect;
-		var xmax = ymax * aspect;
-
-		return this.makeFrustum( xmin, xmax, ymin, ymax, near, far );
-
-	},
-
-	makeOrthographic: function ( left, right, top, bottom, near, far ) {
-
-		var te = this.elements;
-		var w = right - left;
-		var h = top - bottom;
-		var p = far - near;
-
-		var x = ( right + left ) / w;
-		var y = ( top + bottom ) / h;
-		var z = ( far + near ) / p;
-
-		te[0] = 2 / w;	te[4] = 0;	te[8] = 0;	te[12] = -x;
-		te[1] = 0;	te[5] = 2 / h;	te[9] = 0;	te[13] = -y;
-		te[2] = 0;	te[6] = 0;	te[10] = -2/p;	te[14] = -z;
-		te[3] = 0;	te[7] = 0;	te[11] = 0;	te[15] = 1;
-
-		return this;
-
-	},
-
-	clone: function () {
-
-		var te = this.elements;
-
-		return new THREE.Matrix4(
-
-			te[0], te[4], te[8], te[12],
-			te[1], te[5], te[9], te[13],
-			te[2], te[6], te[10], te[14],
-			te[3], te[7], te[11], te[15]
-
-		);
-
-	}
-
-};
-
-THREE.extend( THREE.Matrix4.prototype, {
-
-	decompose: function() {
-
-		var x = new THREE.Vector3();
-		var y = new THREE.Vector3();
-		var z = new THREE.Vector3();
-		var matrix = new THREE.Matrix4();
-
-		return function ( position, quaternion, scale ) {
-
-			var te = this.elements;
-
-			// grab the axis vectors
-			x.set( te[0], te[1], te[2] );
-			y.set( te[4], te[5], te[6] );
-			z.set( te[8], te[9], te[10] );
-
-			position = ( position instanceof THREE.Vector3 ) ? position : new THREE.Vector3();
-			quaternion = ( quaternion instanceof THREE.Quaternion ) ? quaternion : new THREE.Quaternion();
-			scale = ( scale instanceof THREE.Vector3 ) ? scale : new THREE.Vector3();
-
-			scale.x = x.length();
-			scale.y = y.length();
-			scale.z = z.length();
-
-			position.x = te[12];
-			position.y = te[13];
-			position.z = te[14];
-
-			// scale the rotation part
-
-			matrix.copy( this );
-
-			matrix.elements[0] /= scale.x;
-			matrix.elements[1] /= scale.x;
-			matrix.elements[2] /= scale.x;
-
-			matrix.elements[4] /= scale.y;
-			matrix.elements[5] /= scale.y;
-			matrix.elements[6] /= scale.y;
-
-			matrix.elements[8] /= scale.z;
-			matrix.elements[9] /= scale.z;
-			matrix.elements[10] /= scale.z;
-
-			quaternion.setFromRotationMatrix( matrix );
-
-			return [ position, quaternion, scale ];
-
-		};
-
-	}()
-
-} );
-/**
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Ray = function ( origin, direction ) {
-
-	this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
-	this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();
-
-};
-
-THREE.Ray.prototype = {
-
-	constructor: THREE.Ray,
-
-	set: function ( origin, direction ) {
-
-		this.origin.copy( origin );
-		this.direction.copy( direction );
-
-		return this;
-
-	},
-
-	copy: function ( ray ) {
-
-		this.origin.copy( ray.origin );
-		this.direction.copy( ray.direction );
-
-		return this;
-
-	},
-
-	at: function( t, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-
-		return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
-
-	},
-
-	recast: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( t ) {
-
-			this.origin.copy( this.at( t, v1 ) );
-
-			return this;
-
-		};
-
-	}(),
-
-	closestPointToPoint: function ( point, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		result.subVectors( point, this.origin );
-		var directionDistance = result.dot( this.direction );
-
-		return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
-
-	},
-
-	distanceToPoint: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( point ) {
-
-			var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
-			v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
-
-			return v1.distanceTo( point );
-
-		};
-
-	}(),
-
-	isIntersectionSphere: function( sphere ) {
-
-		return ( this.distanceToPoint( sphere.center ) <= sphere.radius );
-
-	},
-
-	isIntersectionPlane: function ( plane ) {
-
-		// check if the line and plane are non-perpendicular, if they
-		// eventually they will intersect.
-		var denominator = plane.normal.dot( this.direction );
-		if ( denominator != 0 ) {
-
-			return true;
-
-		}
-
-		// line is coplanar, return origin
-		if( plane.distanceToPoint( this.origin ) == 0 ) {
-
-			return true;
-
-		}
-
-		return false;
-
-	},
-
-	distanceToPlane: function ( plane ) {
-
-		var denominator = plane.normal.dot( this.direction );
-		if ( denominator == 0 ) {
-
-			// line is coplanar, return origin
-			if( plane.distanceToPoint( this.origin ) == 0 ) {
-
-				return 0;
-
-			}
-
-			// Unsure if this is the correct method to handle this case.
-			return undefined;
-
-		}
-
-		var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
-
-		return t;
-
-	},
-
-	intersectPlane: function ( plane, optionalTarget ) {
-
-		var t = this.distanceToPlane( plane );
-
-		if ( t === undefined ) {
-
-			return undefined;
-		}
-
-		return this.at( t, optionalTarget );
-
-	},
-
-	applyMatrix4: function ( matrix4 ) {
-
-		this.direction.add( this.origin ).applyMatrix4( matrix4 );
-		this.origin.applyMatrix4( matrix4 );
-		this.direction.sub( this.origin );
-
-		return this;
-	},
-
-	equals: function ( ray ) {
-
-		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Ray().copy( this );
-
-	}
-
-};
-/**
- * @author bhouston / http://exocortex.com
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Sphere = function ( center, radius ) {
-
-	this.center = ( center !== undefined ) ? center : new THREE.Vector3();
-	this.radius = ( radius !== undefined ) ? radius : 0;
-
-};
-
-THREE.Sphere.prototype = {
-
-	constructor: THREE.Sphere,
-
-	set: function ( center, radius ) {
-
-		this.center.copy( center );
-		this.radius = radius;
-
-		return this;
-	},
-
-	setFromCenterAndPoints: function ( center, points ) {
-
-		var maxRadiusSq = 0;
-
-		for ( var i = 0, il = points.length; i < il; i ++ ) {
-
-			var radiusSq = center.distanceToSquared( points[ i ] );
-			maxRadiusSq = Math.max( maxRadiusSq, radiusSq );
-
-		}
-
-		this.center = center;
-		this.radius = Math.sqrt( maxRadiusSq );
-
-		return this;
-
-	},
-
-	copy: function ( sphere ) {
-
-		this.center.copy( sphere.center );
-		this.radius = sphere.radius;
-
-		return this;
-
-	},
-
-	empty: function () {
-
-		return ( this.radius <= 0 );
-
-	},
-
-	containsPoint: function ( point ) {
-
-		return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
-
-	},
-
-	distanceToPoint: function ( point ) {
-
-		return ( point.distanceTo( this.center ) - this.radius );
-
-	},
-
-	intersectsSphere: function ( sphere ) {
-
-		var radiusSum = this.radius + sphere.radius;
-
-		return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
-
-	},
-
-	clampPoint: function ( point, optionalTarget ) {
-
-		var deltaLengthSq = this.center.distanceToSquared( point );
-
-		var result = optionalTarget || new THREE.Vector3();
-		result.copy( point );
-
-		if ( deltaLengthSq > ( this.radius * this.radius ) ) {
-
-			result.sub( this.center ).normalize();
-			result.multiplyScalar( this.radius ).add( this.center );
-
-		}
-
-		return result;
-
-	},
-
-	getBoundingBox: function ( optionalTarget ) {
-
-		var box = optionalTarget || new THREE.Box3();
-
-		box.set( this.center, this.center );
-		box.expandByScalar( this.radius );
-
-		return box;
-
-	},
-
-	applyMatrix4: function ( matrix ) {
-
-		this.center.applyMatrix4( matrix );
-		this.radius = this.radius * matrix.getMaxScaleOnAxis();
-
-		return this;
-
-	},
-
-	translate: function ( offset ) {
-
-		this.center.add( offset );
-
-		return this;
-
-	},
-
-	equals: function ( sphere ) {
-
-		return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Sphere().copy( this );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) {
-
-	this.planes = [
-
-		( p0 !== undefined ) ? p0 : new THREE.Plane(),
-		( p1 !== undefined ) ? p1 : new THREE.Plane(),
-		( p2 !== undefined ) ? p2 : new THREE.Plane(),
-		( p3 !== undefined ) ? p3 : new THREE.Plane(),
-		( p4 !== undefined ) ? p4 : new THREE.Plane(),
-		( p5 !== undefined ) ? p5 : new THREE.Plane()
-
-	];
-
-};
-
-THREE.Frustum.prototype = {
-
-	constructor: THREE.Frustum,
-
-	set: function ( p0, p1, p2, p3, p4, p5 ) {
-
-		var planes = this.planes;
-
-		planes[0].copy( p0 );
-		planes[1].copy( p1 );
-		planes[2].copy( p2 );
-		planes[3].copy( p3 );
-		planes[4].copy( p4 );
-		planes[5].copy( p5 );
-
-		return this;
-
-	},
-
-	copy: function ( frustum ) {
-
-		var planes = this.planes;
-
-		for( var i = 0; i < 6; i ++ ) {
-
-			planes[i].copy( frustum.planes[i] );
-
-		}
-
-		return this;
-
-	},
-
-	setFromMatrix: function ( m ) {
-
-		var planes = this.planes;
-		var me = m.elements;
-		var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
-		var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
-		var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
-		var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];
-
-		planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
-		planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
-		planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
-		planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
-		planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
-		planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
-
-		return this;
-
-	},
-
-	intersectsObject: function () {
-
-		var center = new THREE.Vector3();
-
-		return function ( object ) {
-
-			// this method is expanded inlined for performance reasons.
-
-			var matrix = object.matrixWorld;
-			var planes = this.planes;
-			var negRadius = - object.geometry.boundingSphere.radius * matrix.getMaxScaleOnAxis();
-
-			center.getPositionFromMatrix( matrix );
-
-			for ( var i = 0; i < 6; i ++ ) {
-
-				var distance = planes[ i ].distanceToPoint( center );
-
-				if ( distance < negRadius ) {
-
-					return false;
-
-				}
-
-			}
-
-			return true;
-
-		};
-
-	}(),
-
-	intersectsSphere: function ( sphere ) {
-
-		var planes = this.planes;
-		var center = sphere.center;
-		var negRadius = -sphere.radius;
-
-		for ( var i = 0; i < 6; i ++ ) {
-
-			var distance = planes[ i ].distanceToPoint( center );
-
-			if ( distance < negRadius ) {
-
-				return false;
-
-			}
-
-		}
-
-		return true;
-
-	},
-
-	containsPoint: function ( point ) {
-
-		var planes = this.planes;
-
-		for ( var i = 0; i < 6; i ++ ) {
-
-			if ( planes[ i ].distanceToPoint( point ) < 0 ) {
-
-				return false;
-
-			}
-
-		}
-
-		return true;
-
-	},
-
-	clone: function () {
-
-		return new THREE.Frustum().copy( this );
-
-	}
-
-};
-/**
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Plane = function ( normal, constant ) {
-
-	this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 );
-	this.constant = ( constant !== undefined ) ? constant : 0;
-
-};
-
-THREE.Plane.prototype = {
-
-	constructor: THREE.Plane,
-
-	set: function ( normal, constant ) {
-
-		this.normal.copy( normal );
-		this.constant = constant;
-
-		return this;
-
-	},
-
-	setComponents: function ( x, y, z, w ) {
-
-		this.normal.set( x, y, z );
-		this.constant = w;
-
-		return this;
-
-	},
-
-	setFromNormalAndCoplanarPoint: function ( normal, point ) {
-
-		this.normal.copy( normal );
-		this.constant = - point.dot( this.normal );	// must be this.normal, not normal, as this.normal is normalized
-
-		return this;
-
-	},
-
-	setFromCoplanarPoints: function() {
-
-		var v1 = new THREE.Vector3();
-		var v2 = new THREE.Vector3();
-
-		return function ( a, b, c ) {
-
-			var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
-
-			// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
-
-			this.setFromNormalAndCoplanarPoint( normal, a );
-
-			return this;
-
-		};
-
-	}(),
-
-
-	copy: function ( plane ) {
-
-		this.normal.copy( plane.normal );
-		this.constant = plane.constant;
-
-		return this;
-
-	},
-
-	normalize: function () {
-
-		// Note: will lead to a divide by zero if the plane is invalid.
-
-		var inverseNormalLength = 1.0 / this.normal.length();
-		this.normal.multiplyScalar( inverseNormalLength );
-		this.constant *= inverseNormalLength;
-
-		return this;
-
-	},
-
-	negate: function () {
-
-		this.constant *= -1;
-		this.normal.negate();
-
-		return this;
-
-	},
-
-	distanceToPoint: function ( point ) {
-
-		return this.normal.dot( point ) + this.constant;
-
-	},
-
-	distanceToSphere: function ( sphere ) {
-
-		return this.distanceToPoint( sphere.center ) - sphere.radius;
-
-	},
-
-	projectPoint: function ( point, optionalTarget ) {
-
-		return this.orthoPoint( point, optionalTarget ).sub( point ).negate();
-
-	},
-
-	orthoPoint: function ( point, optionalTarget ) {
-
-		var perpendicularMagnitude = this.distanceToPoint( point );
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );
-
-	},
-
-	isIntersectionLine: function ( line ) {
-
-		// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
-
-		var startSign = this.distanceToPoint( line.start );
-		var endSign = this.distanceToPoint( line.end );
-
-		return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
-
-	},
-
-	intersectLine: function() {
-
-		var v1 = new THREE.Vector3();
-
-		return function ( line, optionalTarget ) {
-
-			var result = optionalTarget || new THREE.Vector3();
-
-			var direction = line.delta( v1 );
-
-			var denominator = this.normal.dot( direction );
-
-			if ( denominator == 0 ) {
-
-				// line is coplanar, return origin
-				if( this.distanceToPoint( line.start ) == 0 ) {
-
-					return result.copy( line.start );
-
-				}
-
-				// Unsure if this is the correct method to handle this case.
-				return undefined;
-
-			}
-
-			var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
-
-			if( t < 0 || t > 1 ) {
-
-				return undefined;
-
-			}
-
-			return result.copy( direction ).multiplyScalar( t ).add( line.start );
-
-		};
-
-	}(),
-
-
-	coplanarPoint: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.copy( this.normal ).multiplyScalar( - this.constant );
-
-	},
-
-	applyMatrix4: function() {
-
-		var v1 = new THREE.Vector3();
-		var v2 = new THREE.Vector3();
-
-		return function ( matrix, optionalNormalMatrix ) {
-
-			// compute new normal based on theory here:
-			// http://www.songho.ca/opengl/gl_normaltransform.html
-			optionalNormalMatrix = optionalNormalMatrix || new THREE.Matrix3().getNormalMatrix( matrix );
-			var newNormal = v1.copy( this.normal ).applyMatrix3( optionalNormalMatrix );
-
-			var newCoplanarPoint = this.coplanarPoint( v2 );
-			newCoplanarPoint.applyMatrix4( matrix );
-
-			this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint );
-
-			return this;
-
-		};
-
-	}(),
-
-	translate: function ( offset ) {
-
-		this.constant = this.constant - offset.dot( this.normal );
-
-		return this;
-
-	},
-
-	equals: function ( plane ) {
-
-		return plane.normal.equals( this.normal ) && ( plane.constant == this.constant );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Plane().copy( this );
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Math = {
-
-	// Clamp value to range <a, b>
-
-	clamp: function ( x, a, b ) {
-
-		return ( x < a ) ? a : ( ( x > b ) ? b : x );
-
-	},
-
-	// Clamp value to range <a, inf)
-
-	clampBottom: function ( x, a ) {
-
-		return x < a ? a : x;
-
-	},
-
-	// Linear mapping from range <a1, a2> to range <b1, b2>
-
-	mapLinear: function ( x, a1, a2, b1, b2 ) {
-
-		return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
-
-	},
-
-	// http://en.wikipedia.org/wiki/Smoothstep
-
-	smoothstep: function ( x, min, max ) {
-
-		if ( x <= min ) return 0;
-		if ( x >= max ) return 1;
-
-		x = ( x - min )/( max - min );
-
-		return x*x*(3 - 2*x);
-
-	},
-
-	smootherstep: function ( x, min, max ) {
-
-		if ( x <= min ) return 0;
-		if ( x >= max ) return 1;
-
-		x = ( x - min )/( max - min );
-
-		return x*x*x*(x*(x*6 - 15) + 10);
-
-	},
-
-	// Random float from <0, 1> with 16 bits of randomness
-	// (standard Math.random() creates repetitive patterns when applied over larger space)
-
-	random16: function () {
-
-		return ( 65280 * Math.random() + 255 * Math.random() ) / 65535;
-
-	},
-
-	// Random integer from <low, high> interval
-
-	randInt: function ( low, high ) {
-
-		return low + Math.floor( Math.random() * ( high - low + 1 ) );
-
-	},
-
-	// Random float from <low, high> interval
-
-	randFloat: function ( low, high ) {
-
-		return low + Math.random() * ( high - low );
-
-	},
-
-	// Random float from <-range/2, range/2> interval
-
-	randFloatSpread: function ( range ) {
-
-		return range * ( 0.5 - Math.random() );
-
-	},
-
-	sign: function ( x ) {
-
-		return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 );
-
-	},
-
-	degToRad: function() {
-
-		var degreeToRadiansFactor = Math.PI / 180;
-
-		return function ( degrees ) {
-
-			return degrees * degreeToRadiansFactor;
-
-		};
-
-	}(),
-
-	radToDeg: function() {
-
-		var radianToDegreesFactor = 180 / Math.PI;
-
-		return function ( radians ) {
-
-			return radians * radianToDegreesFactor;
-
-		};
-
-	}()
-
-};
-/**
- * Spline from Tween.js, slightly optimized (and trashed)
- * http://sole.github.com/tween.js/examples/05_spline.html
- *
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Spline = function ( points ) {
-
-	this.points = points;
-
-	var c = [], v3 = { x: 0, y: 0, z: 0 },
-	point, intPoint, weight, w2, w3,
-	pa, pb, pc, pd;
-
-	this.initFromArray = function( a ) {
-
-		this.points = [];
-
-		for ( var i = 0; i < a.length; i++ ) {
-
-			this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };
-
-		}
-
-	};
-
-	this.getPoint = function ( k ) {
-
-		point = ( this.points.length - 1 ) * k;
-		intPoint = Math.floor( point );
-		weight = point - intPoint;
-
-		c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
-		c[ 1 ] = intPoint;
-		c[ 2 ] = intPoint  > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;
-		c[ 3 ] = intPoint  > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;
-
-		pa = this.points[ c[ 0 ] ];
-		pb = this.points[ c[ 1 ] ];
-		pc = this.points[ c[ 2 ] ];
-		pd = this.points[ c[ 3 ] ];
-
-		w2 = weight * weight;
-		w3 = weight * w2;
-
-		v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );
-		v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );
-		v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );
-
-		return v3;
-
-	};
-
-	this.getControlPointsArray = function () {
-
-		var i, p, l = this.points.length,
-			coords = [];
-
-		for ( i = 0; i < l; i ++ ) {
-
-			p = this.points[ i ];
-			coords[ i ] = [ p.x, p.y, p.z ];
-
-		}
-
-		return coords;
-
-	};
-
-	// approximate length by summing linear segments
-
-	this.getLength = function ( nSubDivisions ) {
-
-		var i, index, nSamples, position,
-			point = 0, intPoint = 0, oldIntPoint = 0,
-			oldPosition = new THREE.Vector3(),
-			tmpVec = new THREE.Vector3(),
-			chunkLengths = [],
-			totalLength = 0;
-
-		// first point has 0 length
-
-		chunkLengths[ 0 ] = 0;
-
-		if ( !nSubDivisions ) nSubDivisions = 100;
-
-		nSamples = this.points.length * nSubDivisions;
-
-		oldPosition.copy( this.points[ 0 ] );
-
-		for ( i = 1; i < nSamples; i ++ ) {
-
-			index = i / nSamples;
-
-			position = this.getPoint( index );
-			tmpVec.copy( position );
-
-			totalLength += tmpVec.distanceTo( oldPosition );
-
-			oldPosition.copy( position );
-
-			point = ( this.points.length - 1 ) * index;
-			intPoint = Math.floor( point );
-
-			if ( intPoint != oldIntPoint ) {
-
-				chunkLengths[ intPoint ] = totalLength;
-				oldIntPoint = intPoint;
-
-			}
-
-		}
-
-		// last point ends with total length
-
-		chunkLengths[ chunkLengths.length ] = totalLength;
-
-		return { chunks: chunkLengths, total: totalLength };
-
-	};
-
-	this.reparametrizeByArcLength = function ( samplingCoef ) {
-
-		var i, j,
-			index, indexCurrent, indexNext,
-			linearDistance, realDistance,
-			sampling, position,
-			newpoints = [],
-			tmpVec = new THREE.Vector3(),
-			sl = this.getLength();
-
-		newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );
-
-		for ( i = 1; i < this.points.length; i++ ) {
-
-			//tmpVec.copy( this.points[ i - 1 ] );
-			//linearDistance = tmpVec.distanceTo( this.points[ i ] );
-
-			realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];
-
-			sampling = Math.ceil( samplingCoef * realDistance / sl.total );
-
-			indexCurrent = ( i - 1 ) / ( this.points.length - 1 );
-			indexNext = i / ( this.points.length - 1 );
-
-			for ( j = 1; j < sampling - 1; j++ ) {
-
-				index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );
-
-				position = this.getPoint( index );
-				newpoints.push( tmpVec.copy( position ).clone() );
-
-			}
-
-			newpoints.push( tmpVec.copy( this.points[ i ] ).clone() );
-
-		}
-
-		this.points = newpoints;
-
-	};
-
-	// Catmull-Rom
-
-	function interpolate( p0, p1, p2, p3, t, t2, t3 ) {
-
-		var v0 = ( p2 - p0 ) * 0.5,
-			v1 = ( p3 - p1 ) * 0.5;
-
-		return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
-
-	};
-
-};
-/**
- * @author bhouston / http://exocortex.com
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Triangle = function ( a, b, c ) {
-
-	this.a = ( a !== undefined ) ? a : new THREE.Vector3();
-	this.b = ( b !== undefined ) ? b : new THREE.Vector3();
-	this.c = ( c !== undefined ) ? c : new THREE.Vector3();
-
-};
-
-THREE.Triangle.normal = function() {
-
-	var v0 = new THREE.Vector3();
-
-	return function ( a, b, c, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-
-		result.subVectors( c, b );
-		v0.subVectors( a, b );
-		result.cross( v0 );
-
-		var resultLengthSq = result.lengthSq();
-		if( resultLengthSq > 0 ) {
-
-			return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
-
-		}
-
-		return result.set( 0, 0, 0 );
-
-	};
-
-}();
-
-// static/instance method to calculate barycoordinates
-// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
-THREE.Triangle.barycoordFromPoint = function() {
-
-	var v0 = new THREE.Vector3();
-	var v1 = new THREE.Vector3();
-	var v2 = new THREE.Vector3();
-
-	return function ( point, a, b, c, optionalTarget ) {
-
-		v0.subVectors( c, a );
-		v1.subVectors( b, a );
-		v2.subVectors( point, a );
-
-		var dot00 = v0.dot( v0 );
-		var dot01 = v0.dot( v1 );
-		var dot02 = v0.dot( v2 );
-		var dot11 = v1.dot( v1 );
-		var dot12 = v1.dot( v2 );
-
-		var denom = ( dot00 * dot11 - dot01 * dot01 );
-
-		var result = optionalTarget || new THREE.Vector3();
-
-		// colinear or singular triangle
-		if( denom == 0 ) {
-			// arbitrary location outside of triangle?
-			// not sure if this is the best idea, maybe should be returning undefined
-			return result.set( -2, -1, -1 );
-		}
-
-		var invDenom = 1 / denom;
-		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
-
-		// barycoordinates must always sum to 1
-		return result.set( 1 - u - v, v, u );
-
-	};
-
-}();
-
-THREE.Triangle.containsPoint = function() {
-
-	var v1 = new THREE.Vector3();
-
-	return function ( point, a, b, c ) {
-
-		var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 );
-
-		return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
-
-	};
-
-}();
-
-THREE.Triangle.prototype = {
-
-	constructor: THREE.Triangle,
-
-	set: function ( a, b, c ) {
-
-		this.a.copy( a );
-		this.b.copy( b );
-		this.c.copy( c );
-
-		return this;
-
-	},
-
-	setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
-
-		this.a.copy( points[i0] );
-		this.b.copy( points[i1] );
-		this.c.copy( points[i2] );
-
-		return this;
-
-	},
-
-	copy: function ( triangle ) {
-
-		this.a.copy( triangle.a );
-		this.b.copy( triangle.b );
-		this.c.copy( triangle.c );
-
-		return this;
-
-	},
-
-	area: function() {
-
-		var v0 = new THREE.Vector3();
-		var v1 = new THREE.Vector3();
-
-		return function () {
-
-			v0.subVectors( this.c, this.b );
-			v1.subVectors( this.a, this.b );
-
-			return v0.cross( v1 ).length() * 0.5;
-
-		};
-
-	}(),
-
-	midpoint: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
-		return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
-
-	},
-
-	normal: function ( optionalTarget ) {
-
-		return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget );
-
-	},
-
-	plane: function ( optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Plane();
-
-		return result.setFromCoplanarPoints( this.a, this.b, this.c );
-
-	},
-
-	barycoordFromPoint: function ( point, optionalTarget ) {
-
-		return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
-
-	},
-
-	containsPoint: function ( point ) {
-
-		return THREE.Triangle.containsPoint( point, this.a, this.b, this.c );
-
-	},
-
-	equals: function ( triangle ) {
-
-		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
-
-	},
-
-	clone: function () {
-
-		return new THREE.Triangle().copy( this );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Vertex = function ( v ) {
-
-	console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.')
-	return v;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.UV = function ( u, v ) {
-
-	console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.')
-	return new THREE.Vector2( u, v );
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Clock = function ( autoStart ) {
-
-	this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
-
-	this.startTime = 0;
-	this.oldTime = 0;
-	this.elapsedTime = 0;
-
-	this.running = false;
-
-};
-
-THREE.Clock.prototype = {
-
-	constructor: THREE.Clock,
-
-	start: function () {
-
-		this.startTime = window.performance !== undefined && window.performance.now !== undefined
-					? window.performance.now()
-					: Date.now();
-
-		this.oldTime = this.startTime;
-		this.running = true;
-	},
-
-	stop: function () {
-
-		this.getElapsedTime();
-		this.running = false;
-
-	},
-
-	getElapsedTime: function () {
-
-		this.getDelta();
-		return this.elapsedTime;
-
-	},
-
-	getDelta: function () {
-
-		var diff = 0;
-
-		if ( this.autoStart && ! this.running ) {
-
-			this.start();
-
-		}
-
-		if ( this.running ) {
-
-			var newTime = window.performance !== undefined && window.performance.now !== undefined
-					? window.performance.now()
-					: Date.now();
-
-			diff = 0.001 * ( newTime - this.oldTime );
-			this.oldTime = newTime;
-
-			this.elapsedTime += diff;
-
-		}
-
-		return diff;
-
-	}
-
-};
-/**
- * https://github.com/mrdoob/eventdispatcher.js/
- */
-
-THREE.EventDispatcher = function () {}
-
-THREE.EventDispatcher.prototype = {
-
-	constructor: THREE.EventDispatcher,
-
-	addEventListener: function ( type, listener ) {
-
-		if ( this._listeners === undefined ) this._listeners = {};
-
-		var listeners = this._listeners;
-
-		if ( listeners[ type ] === undefined ) {
-
-			listeners[ type ] = [];
-
-		}
-
-		if ( listeners[ type ].indexOf( listener ) === - 1 ) {
-
-			listeners[ type ].push( listener );
-
-		}
-
-	},
-
-	hasEventListener: function ( type, listener ) {
-
-		if ( this._listeners === undefined ) return false;
-
-		var listeners = this._listeners;
-
-		if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
-
-			return true;
-
-		}
-
-		return false;
-
-	},
-
-	removeEventListener: function ( type, listener ) {
-
-		if ( this._listeners === undefined ) return;
-
-		var listeners = this._listeners;
-		var index = listeners[ type ].indexOf( listener );
-
-		if ( index !== - 1 ) {
-
-			listeners[ type ].splice( index, 1 );
-
-		}
-
-	},
-
-	dispatchEvent: function ( event ) {
-
-		if ( this._listeners === undefined ) return;
-
-		var listeners = this._listeners;
-		var listenerArray = listeners[ event.type ];
-
-		if ( listenerArray !== undefined ) {
-
-			event.target = this;
-
-			for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
-
-				listenerArray[ i ].call( this, event );
-
-			}
-
-		}
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author bhouston / http://exocortex.com/
- */
-
-( function ( THREE ) {
-
-	THREE.Raycaster = function ( origin, direction, near, far ) {
-
-		this.ray = new THREE.Ray( origin, direction );
-
-		// normalized ray.direction required for accurate distance calculations
-		if ( this.ray.direction.lengthSq() > 0 ) {
-
-			this.ray.direction.normalize();
-
-		}
-
-		this.near = near || 0;
-		this.far = far || Infinity;
-
-	};
-
-	var sphere = new THREE.Sphere();
-	var localRay = new THREE.Ray();
-	var facePlane = new THREE.Plane();
-	var intersectPoint = new THREE.Vector3();
-	var matrixPosition = new THREE.Vector3();
-
-	var inverseMatrix = new THREE.Matrix4();
-
-	var descSort = function ( a, b ) {
-
-		return a.distance - b.distance;
-
-	};
-
-	var intersectObject = function ( object, raycaster, intersects ) {
-
-		if ( object instanceof THREE.Particle ) {
-
-			matrixPosition.getPositionFromMatrix( object.matrixWorld );
-			var distance = raycaster.ray.distanceToPoint( matrixPosition );
-
-			if ( distance > object.scale.x ) {
-
-				return intersects;
-
-			}
-
-			intersects.push( {
-
-				distance: distance,
-				point: object.position,
-				face: null,
-				object: object
-
-			} );
-
-		} else if ( object instanceof THREE.LOD ) {
-
-			matrixPosition.getPositionFromMatrix( object.matrixWorld );
-			var distance = raycaster.ray.origin.distanceTo( matrixPosition );
-
-			intersectObject( object.getObjectForDistance( distance ), raycaster, intersects );
-
-		} else if ( object instanceof THREE.Mesh ) {
-
-			// Checking boundingSphere distance to ray
-			matrixPosition.getPositionFromMatrix( object.matrixWorld );
-			sphere.set(
-				matrixPosition,
-				object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() );
-
-			if ( ! raycaster.ray.isIntersectionSphere( sphere ) ) {
-
-				return intersects;
-
-			}
-
-			// Checking faces
-
-			var geometry = object.geometry;
-			var vertices = geometry.vertices;
-
-			var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
-			var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
-
-			var side = object.material.side;
-
-			var a, b, c, d;
-			var precision = raycaster.precision;
-
-			inverseMatrix.getInverse( object.matrixWorld );
-
-			localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-
-			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
-
-				var face = geometry.faces[ f ];
-
-				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;
-
-				if ( material === undefined ) continue;
-
-				facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] );
-
-				var planeDistance = localRay.distanceToPlane( facePlane );
-
-				// bail if raycaster and plane are parallel
-				if ( Math.abs( planeDistance ) < precision ) continue;
-
-				// if negative distance, then plane is behind raycaster
-				if ( planeDistance < 0 ) continue;
-
-				// check if we hit the wrong side of a single sided face
-				side = material.side;
-				if ( side !== THREE.DoubleSide ) {
-
-					var planeSign = localRay.direction.dot( facePlane.normal );
-
-					if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue;
-
-				}
-
-				// this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
-				if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue;
-
-				intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy
-
-				if ( face instanceof THREE.Face3 ) {
-
-					a = vertices[ face.a ];
-					b = vertices[ face.b ];
-					c = vertices[ face.c ];
-
-					if ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, c ) ) continue;
-
-				} else if ( face instanceof THREE.Face4 ) {
-
-					a = vertices[ face.a ];
-					b = vertices[ face.b ];
-					c = vertices[ face.c ];
-					d = vertices[ face.d ];
-
-					if ( ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, d ) ) &&
-						 ( ! THREE.Triangle.containsPoint( intersectPoint, b, c, d ) ) ) continue;
-
-				} else {
-
-					// This is added because if we call out of this if/else group when none of the cases
-					//    match it will add a point to the intersection list erroneously.
-					throw Error( "face type not supported" );
-
-				}
-
-				intersects.push( {
-
-					distance: planeDistance,	// this works because the original ray was normalized, and the transformed localRay wasn't
-					point: raycaster.ray.at( planeDistance ),
-					face: face,
-					faceIndex: f,
-					object: object
-
-				} );
-
-			}
-
-		}
-
-	};
-
-	var intersectDescendants = function ( object, raycaster, intersects ) {
-
-		var descendants = object.getDescendants();
-
-		for ( var i = 0, l = descendants.length; i < l; i ++ ) {
-
-			intersectObject( descendants[ i ], raycaster, intersects );
-
-		}
-	};
-
-	//
-
-	THREE.Raycaster.prototype.precision = 0.0001;
-
-	THREE.Raycaster.prototype.set = function ( origin, direction ) {
-
-		this.ray.set( origin, direction );
-
-		// normalized ray.direction required for accurate distance calculations
-		if ( this.ray.direction.length() > 0 ) {
-
-			this.ray.direction.normalize();
-
-		}
-
-	};
-
-	THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {
-
-		var intersects = [];
-
-		if ( recursive === true ) {
-
-			intersectDescendants( object, this, intersects );
-
-		}
-
-		intersectObject( object, this, intersects );
-
-		intersects.sort( descSort );
-
-		return intersects;
-
-	};
-
-	THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {
-
-		var intersects = [];
-
-		for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-			intersectObject( objects[ i ], this, intersects );
-
-			if ( recursive === true ) {
-
-				intersectDescendants( objects[ i ], this, intersects );
-
-			}
-		}
-
-		intersects.sort( descSort );
-
-		return intersects;
-
-	};
-
-}( THREE ) );
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author WestLangley / http://github.com/WestLangley
- */
-
-THREE.Object3D = function () {
-
-	this.id = THREE.Object3DIdCount ++;
-
-	this.name = '';
-
-	this.parent = undefined;
-	this.children = [];
-
-	this.up = new THREE.Vector3( 0, 1, 0 );
-
-	this.position = new THREE.Vector3();
-	this.rotation = new THREE.Vector3();
-	this.eulerOrder = THREE.Object3D.defaultEulerOrder;
-	this.scale = new THREE.Vector3( 1, 1, 1 );
-
-	this.renderDepth = null;
-
-	this.rotationAutoUpdate = true;
-
-	this.matrix = new THREE.Matrix4();
-	this.matrixWorld = new THREE.Matrix4();
-
-	this.matrixAutoUpdate = true;
-	this.matrixWorldNeedsUpdate = true;
-
-	this.quaternion = new THREE.Quaternion();
-	this.useQuaternion = false;
-
-	this.visible = true;
-
-	this.castShadow = false;
-	this.receiveShadow = false;
-
-	this.frustumCulled = true;
-
-	this.userData = {};
-
-};
-
-
-THREE.Object3D.prototype = {
-
-	constructor: THREE.Object3D,
-
-	applyMatrix: function () {
-
-		var m1 = new THREE.Matrix4();
-
-		return function ( matrix ) {
-
-			this.matrix.multiplyMatrices( matrix, this.matrix );
-
-			this.position.getPositionFromMatrix( this.matrix );
-
-			this.scale.getScaleFromMatrix( this.matrix );
-
-			m1.extractRotation( this.matrix );
-
-			if ( this.useQuaternion === true )  {
-
-				this.quaternion.setFromRotationMatrix( m1 );
-
-			} else {
-
-				this.rotation.setEulerFromRotationMatrix( m1, this.eulerOrder );
-
-			}
-
-		}
-
-	}(),
-
-	rotateOnAxis: function() {
-
-		// rotate object on axis in object space
-		// axis is assumed to be normalized
-
-		var q1 = new THREE.Quaternion();
-		var q2 = new THREE.Quaternion();
-
-		return function ( axis, angle ) {
-
-			q1.setFromAxisAngle( axis, angle );
-
-			if ( this.useQuaternion === true ) {
-
-				this.quaternion.multiply( q1 );
-
-			} else {
-
-				q2.setFromEuler( this.rotation, this.eulerOrder );
-				q2.multiply( q1 );
-
-				this.rotation.setEulerFromQuaternion( q2, this.eulerOrder );
-
-			}
-
-			return this;
-
-		}
-
-	}(),
-
-	translateOnAxis: function () {
-
-		// translate object by distance along axis in object space
-		// axis is assumed to be normalized
-
-		var v1 = new THREE.Vector3();
-
-		return function ( axis, distance ) {
-
-			v1.copy( axis );
-
-			if ( this.useQuaternion === true ) {
-
-				v1.applyQuaternion( this.quaternion );
-
-			} else {
-
-				v1.applyEuler( this.rotation, this.eulerOrder );
-
-			}
-
-			this.position.add( v1.multiplyScalar( distance ) );
-
-			return this;
-
-		}
-
-	}(),
-
-	translate: function ( distance, axis ) {
-
-		console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' );
-		return this.translateOnAxis( axis, distance );
-
-	},
-
-	translateX: function () {
-
-		var v1 = new THREE.Vector3( 1, 0, 0 );
-
-		return function ( distance ) {
-
-			return this.translateOnAxis( v1, distance );
-
-		};
-
-	}(),
-
-	translateY: function () {
-
-		var v1 = new THREE.Vector3( 0, 1, 0 );
-
-		return function ( distance ) {
-
-			return this.translateOnAxis( v1, distance );
-
-		};
-
-	}(),
-
-	translateZ: function () {
-
-		var v1 = new THREE.Vector3( 0, 0, 1 );
-
-		return function ( distance ) {
-
-			return this.translateOnAxis( v1, distance );
-
-		};
-
-	}(),
-
-	localToWorld: function ( vector ) {
-
-		return vector.applyMatrix4( this.matrixWorld );
-
-	},
-
-	worldToLocal: function () {
-
-		var m1 = new THREE.Matrix4();
-
-		return function ( vector ) {
-
-			return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
-
-		};
-
-	}(),
-
-	lookAt: function () {
-
-		// This routine does not support objects with rotated and/or translated parent(s)
-
-		var m1 = new THREE.Matrix4();
-
-		return function ( vector ) {
-
-			m1.lookAt( vector, this.position, this.up );
-
-			if ( this.useQuaternion === true )  {
-
-				this.quaternion.setFromRotationMatrix( m1 );
-
-			} else {
-
-				this.rotation.setEulerFromRotationMatrix( m1, this.eulerOrder );
-
-			}
-
-		};
-
-	}(),
-
-	add: function ( object ) {
-
-		if ( object === this ) {
-
-			console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
-			return;
-
-		}
-
-		if ( object instanceof THREE.Object3D ) {
-
-			if ( object.parent !== undefined ) {
-
-				object.parent.remove( object );
-
-			}
-
-			object.parent = this;
-			this.children.push( object );
-
-			// add to scene
-
-			var scene = this;
-
-			while ( scene.parent !== undefined ) {
-
-				scene = scene.parent;
-
-			}
-
-			if ( scene !== undefined && scene instanceof THREE.Scene )  {
-
-				scene.__addObject( object );
-
-			}
-
-		}
-
-	},
-
-	remove: function ( object ) {
-
-		var index = this.children.indexOf( object );
-
-		if ( index !== - 1 ) {
-
-			object.parent = undefined;
-			this.children.splice( index, 1 );
-
-			// remove from scene
-
-			var scene = this;
-
-			while ( scene.parent !== undefined ) {
-
-				scene = scene.parent;
-
-			}
-
-			if ( scene !== undefined && scene instanceof THREE.Scene ) {
-
-				scene.__removeObject( object );
-
-			}
-
-		}
-
-	},
-
-	traverse: function ( callback ) {
-
-		callback( this );
-
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-			this.children[ i ].traverse( callback );
-
-		}
-
-	},
-
-	getObjectById: function ( id, recursive ) {
-
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-			var child = this.children[ i ];
-
-			if ( child.id === id ) {
-
-				return child;
-
-			}
-
-			if ( recursive === true ) {
-
-				child = child.getObjectById( id, recursive );
-
-				if ( child !== undefined ) {
-
-					return child;
-
-				}
-
-			}
-
-		}
-
-		return undefined;
-
-	},
-
-	getObjectByName: function ( name, recursive ) {
-
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-			var child = this.children[ i ];
-
-			if ( child.name === name ) {
-
-				return child;
-
-			}
-
-			if ( recursive === true ) {
-
-				child = child.getObjectByName( name, recursive );
-
-				if ( child !== undefined ) {
-
-					return child;
-
-				}
-
-			}
-
-		}
-
-		return undefined;
-
-	},
-
-	getChildByName: function ( name, recursive ) {
-
-		console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' );
-		return this.getObjectByName( name, recursive );
-
-	},
-
-	getDescendants: function ( array ) {
-
-		if ( array === undefined ) array = [];
-
-		Array.prototype.push.apply( array, this.children );
-
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-			this.children[ i ].getDescendants( array );
-
-		}
-
-		return array;
-
-	},
-
-	updateMatrix: function () {
-
-		// if we are not using a quaternion directly, convert Euler rotation to this.quaternion.
-
-		if ( this.useQuaternion === false )  {
-
-			this.matrix.makeFromPositionEulerScale( this.position, this.rotation, this.eulerOrder, this.scale );
-
-		} else {
-
-			this.matrix.makeFromPositionQuaternionScale( this.position, this.quaternion, this.scale );
-
-		}
-
-		this.matrixWorldNeedsUpdate = true;
-
-	},
-
-	updateMatrixWorld: function ( force ) {
-
-		if ( this.matrixAutoUpdate === true ) this.updateMatrix();
-
-		if ( this.matrixWorldNeedsUpdate === true || force === true ) {
-
-			if ( this.parent === undefined ) {
-
-				this.matrixWorld.copy( this.matrix );
-
-			} else {
-
-				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
-
-			}
-
-			this.matrixWorldNeedsUpdate = false;
-
-			force = true;
-
-		}
-
-		// update children
-
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-			this.children[ i ].updateMatrixWorld( force );
-
-		}
-
-	},
-
-	clone: function ( object ) {
-
-		if ( object === undefined ) object = new THREE.Object3D();
-
-		object.name = this.name;
-
-		object.up.copy( this.up );
-
-		object.position.copy( this.position );
-		if ( object.rotation instanceof THREE.Vector3 ) object.rotation.copy( this.rotation ); // because of Sprite madness
-		object.eulerOrder = this.eulerOrder;
-		object.scale.copy( this.scale );
-
-		object.renderDepth = this.renderDepth;
-
-		object.rotationAutoUpdate = this.rotationAutoUpdate;
-
-		object.matrix.copy( this.matrix );
-		object.matrixWorld.copy( this.matrixWorld );
-
-		object.matrixAutoUpdate = this.matrixAutoUpdate;
-		object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;
-
-		object.quaternion.copy( this.quaternion );
-		object.useQuaternion = this.useQuaternion;
-
-		object.visible = this.visible;
-
-		object.castShadow = this.castShadow;
-		object.receiveShadow = this.receiveShadow;
-
-		object.frustumCulled = this.frustumCulled;
-
-		object.userData = JSON.parse( JSON.stringify( this.userData ) );
-
-		for ( var i = 0; i < this.children.length; i ++ ) {
-
-			var child = this.children[ i ];
-			object.add( child.clone() );
-
-		}
-
-		return object;
-
-	}
-
-};
-
-THREE.Object3D.defaultEulerOrder = 'XYZ',
-
-THREE.Object3DIdCount = 0;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author julianwa / https://github.com/julianwa
- */
-
-THREE.Projector = function () {
-
-	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
-	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
-	_face, _face3Count, _face3Pool = [], _face3PoolLength = 0,
-	_face4Count, _face4Pool = [], _face4PoolLength = 0,
-	_line, _lineCount, _linePool = [], _linePoolLength = 0,
-	_particle, _particleCount, _particlePool = [], _particlePoolLength = 0,
-
-	_renderData = { objects: [], sprites: [], lights: [], elements: [] },
-
-	_vector3 = new THREE.Vector3(),
-	_vector4 = new THREE.Vector4(),
-
-	_clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ),
-	_boundingBox = new THREE.Box3(),
-	_points3 = new Array( 3 ),
-	_points4 = new Array( 4 ),
-
-	_viewMatrix = new THREE.Matrix4(),
-	_viewProjectionMatrix = new THREE.Matrix4(),
-
-	_modelMatrix,
-	_modelViewProjectionMatrix = new THREE.Matrix4(),
-
-	_normalMatrix = new THREE.Matrix3(),
-	_normalViewMatrix = new THREE.Matrix3(),
-
-	_centroid = new THREE.Vector3(),
-
-	_frustum = new THREE.Frustum(),
-
-	_clippedVertex1PositionScreen = new THREE.Vector4(),
-	_clippedVertex2PositionScreen = new THREE.Vector4();
-
-	this.projectVector = function ( vector, camera ) {
-
-		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
-		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
-
-		return vector.applyProjection( _viewProjectionMatrix );
-
-	};
-
-	this.unprojectVector = function ( vector, camera ) {
-
-		camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
-
-		_viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, camera.projectionMatrixInverse );
-
-		return vector.applyProjection( _viewProjectionMatrix );
-
-	};
-
-	this.pickingRay = function ( vector, camera ) {
-
-		// set two vectors with opposing z values
-		vector.z = -1.0;
-		var end = new THREE.Vector3( vector.x, vector.y, 1.0 );
-
-		this.unprojectVector( vector, camera );
-		this.unprojectVector( end, camera );
-
-		// find direction from vector to end
-		end.sub( vector ).normalize();
-
-		return new THREE.Raycaster( vector, end );
-
-	};
-
-	var projectGraph = function ( root, sortObjects ) {
-
-		_objectCount = 0;
-
-		_renderData.objects.length = 0;
-		_renderData.sprites.length = 0;
-		_renderData.lights.length = 0;
-
-		var projectObject = function ( parent ) {
-
-			for ( var c = 0, cl = parent.children.length; c < cl; c ++ ) {
-
-				var object = parent.children[ c ];
-
-				if ( object.visible === false ) continue;
-
-				if ( object instanceof THREE.Light ) {
-
-					_renderData.lights.push( object );
-
-				} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) {
-
-					if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
-
-						_object = getNextObjectInPool();
-						_object.object = object;
-
-						if ( object.renderDepth !== null ) {
-
-							_object.z = object.renderDepth;
-
-						} else {
-
-							_vector3.getPositionFromMatrix( object.matrixWorld );
-							_vector3.applyProjection( _viewProjectionMatrix );
-							_object.z = _vector3.z;
-
-						}
-
-						_renderData.objects.push( _object );
-
-					}
-
-				} else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) {
-
-					_object = getNextObjectInPool();
-					_object.object = object;
-
-					// TODO: Find an elegant and performant solution and remove this dupe code.
-
-					if ( object.renderDepth !== null ) {
-
-						_object.z = object.renderDepth;
-
-					} else {
-
-						_vector3.getPositionFromMatrix( object.matrixWorld );
-						_vector3.applyProjection( _viewProjectionMatrix );
-						_object.z = _vector3.z;
-
-					}
-
-					_renderData.sprites.push( _object );
-
-				} else {
-
-					_object = getNextObjectInPool();
-					_object.object = object;
-
-					if ( object.renderDepth !== null ) {
-
-						_object.z = object.renderDepth;
-
-					} else {
-
-						_vector3.getPositionFromMatrix( object.matrixWorld );
-						_vector3.applyProjection( _viewProjectionMatrix );
-						_object.z = _vector3.z;
-
-					}
-
-					_renderData.objects.push( _object );
-
-				}
-
-				projectObject( object );
-
-			}
-
-		};
-
-		projectObject( root );
-
-		if ( sortObjects === true ) _renderData.objects.sort( painterSort );
-
-		return _renderData;
-
-	};
-
-	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
-
-		var visible = false,
-		o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object,
-		geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs,
-		v1, v2, v3, v4, isFaceMaterial, objectMaterials;
-
-		_face3Count = 0;
-		_face4Count = 0;
-		_lineCount = 0;
-		_particleCount = 0;
-
-		_renderData.elements.length = 0;
-
-		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-		if ( camera.parent === undefined ) camera.updateMatrixWorld();
-
-		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
-		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
-
-		_normalViewMatrix.getNormalMatrix( _viewMatrix );
-
-		_frustum.setFromMatrix( _viewProjectionMatrix );
-
-		_renderData = projectGraph( scene, sortObjects );
-
-		for ( o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
-
-			object = _renderData.objects[ o ].object;
-
-			_modelMatrix = object.matrixWorld;
-
-			_vertexCount = 0;
-
-			if ( object instanceof THREE.Mesh ) {
-
-				geometry = object.geometry;
-
-				vertices = geometry.vertices;
-				faces = geometry.faces;
-				faceVertexUvs = geometry.faceVertexUvs;
-
-				_normalMatrix.getNormalMatrix( _modelMatrix );
-
-				isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
-				objectMaterials = isFaceMaterial === true ? object.material : null;
-
-				for ( v = 0, vl = vertices.length; v < vl; v ++ ) {
-
-					_vertex = getNextVertexInPool();
-
-					_vertex.positionWorld.copy( vertices[ v ] ).applyMatrix4( _modelMatrix );
-					_vertex.positionScreen.copy( _vertex.positionWorld ).applyMatrix4( _viewProjectionMatrix );
-
-					_vertex.positionScreen.x /= _vertex.positionScreen.w;
-					_vertex.positionScreen.y /= _vertex.positionScreen.w;
-					_vertex.positionScreen.z /= _vertex.positionScreen.w;
-
-					_vertex.visible = ! ( _vertex.positionScreen.x < -1 || _vertex.positionScreen.x > 1 ||
-							      _vertex.positionScreen.y < -1 || _vertex.positionScreen.y > 1 ||
-							      _vertex.positionScreen.z < -1 || _vertex.positionScreen.z > 1 );
-
-				}
-
-				for ( f = 0, fl = faces.length; f < fl; f ++ ) {
-
-					face = faces[ f ];
-
-					var material = isFaceMaterial === true
-						? objectMaterials.materials[ face.materialIndex ]
-						: object.material;
-
-					if ( material === undefined ) continue;
-
-					var side = material.side;
-
-					if ( face instanceof THREE.Face3 ) {
-
-						v1 = _vertexPool[ face.a ];
-						v2 = _vertexPool[ face.b ];
-						v3 = _vertexPool[ face.c ];
-
-						_points3[ 0 ] = v1.positionScreen;
-						_points3[ 1 ] = v2.positionScreen;
-						_points3[ 2 ] = v3.positionScreen;
-
-						if ( v1.visible === true || v2.visible === true || v3.visible === true ||
-							_clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) {
-
-							visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
-								( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
-
-							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
-
-								_face = getNextFace3InPool();
-
-								_face.v1.copy( v1 );
-								_face.v2.copy( v2 );
-								_face.v3.copy( v3 );
-
-							} else {
-
-								continue;
-
-							}
-
-						} else {
-
-							continue;
-
-						}
-
-					} else if ( face instanceof THREE.Face4 ) {
-
-						v1 = _vertexPool[ face.a ];
-						v2 = _vertexPool[ face.b ];
-						v3 = _vertexPool[ face.c ];
-						v4 = _vertexPool[ face.d ];
-
-						_points4[ 0 ] = v1.positionScreen;
-						_points4[ 1 ] = v2.positionScreen;
-						_points4[ 2 ] = v3.positionScreen;
-						_points4[ 3 ] = v4.positionScreen;
-
-						if ( v1.visible === true || v2.visible === true || v3.visible === true || v4.visible === true ||
-							_clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points4 ) ) ) {
-
-							visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
-								( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
-								( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
-								( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0;
-
-
-							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
-
-								_face = getNextFace4InPool();
-
-								_face.v1.copy( v1 );
-								_face.v2.copy( v2 );
-								_face.v3.copy( v3 );
-								_face.v4.copy( v4 );
-
-							} else {
-
-								continue;
-
-							}
-
-						} else {
-
-							continue;
-
-						}
-
-					}
-
-					_face.normalModel.copy( face.normal );
-
-					if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
-
-						_face.normalModel.negate();
-
-					}
-
-					_face.normalModel.applyMatrix3( _normalMatrix ).normalize();
-
-					_face.normalModelView.copy( _face.normalModel ).applyMatrix3( _normalViewMatrix );
-
-					_face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix );
-
-					faceVertexNormals = face.vertexNormals;
-
-					for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) {
-
-						var normalModel = _face.vertexNormalsModel[ n ];
-						normalModel.copy( faceVertexNormals[ n ] );
-
-						if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
-
-							normalModel.negate();
-
-						}
-
-						normalModel.applyMatrix3( _normalMatrix ).normalize();
-
-						var normalModelView = _face.vertexNormalsModelView[ n ];
-						normalModelView.copy( normalModel ).applyMatrix3( _normalViewMatrix );
-
-					}
-
-					_face.vertexNormalsLength = faceVertexNormals.length;
-
-					for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) {
-
-						uvs = faceVertexUvs[ c ][ f ];
-
-						if ( uvs === undefined ) continue;
-
-						for ( u = 0, ul = uvs.length; u < ul; u ++ ) {
-
-							_face.uvs[ c ][ u ] = uvs[ u ];
-
-						}
-
-					}
-
-					_face.color = face.color;
-					_face.material = material;
-
-					_centroid.copy( _face.centroidModel ).applyProjection( _viewProjectionMatrix );
-
-					_face.z = _centroid.z;
-
-					_renderData.elements.push( _face );
-
-				}
-
-			} else if ( object instanceof THREE.Line ) {
-
-				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
-
-				vertices = object.geometry.vertices;
-
-				v1 = getNextVertexInPool();
-				v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
-
-				// Handle LineStrip and LinePieces
-				var step = object.type === THREE.LinePieces ? 2 : 1;
-
-				for ( v = 1, vl = vertices.length; v < vl; v ++ ) {
-
-					v1 = getNextVertexInPool();
-					v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
-
-					if ( ( v + 1 ) % step > 0 ) continue;
-
-					v2 = _vertexPool[ _vertexCount - 2 ];
-
-					_clippedVertex1PositionScreen.copy( v1.positionScreen );
-					_clippedVertex2PositionScreen.copy( v2.positionScreen );
-
-					if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
-
-						// Perform the perspective divide
-						_clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
-						_clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
-
-						_line = getNextLineInPool();
-						_line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
-						_line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
-
-						_line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
-
-						_line.material = object.material;
-
-						if ( object.material.vertexColors === THREE.VertexColors ) {
-
-							_line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
-							_line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
-
-						}
-
-						_renderData.elements.push( _line );
-
-					}
-
-				}
-
-			}
-
-		}
-
-		for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {
-
-			object = _renderData.sprites[ o ].object;
-
-			_modelMatrix = object.matrixWorld;
-
-			if ( object instanceof THREE.Particle ) {
-
-				_vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 );
-				_vector4.applyMatrix4( _viewProjectionMatrix );
-
-				_vector4.z /= _vector4.w;
-
-				if ( _vector4.z > 0 && _vector4.z < 1 ) {
-
-					_particle = getNextParticleInPool();
-					_particle.object = object;
-					_particle.x = _vector4.x / _vector4.w;
-					_particle.y = _vector4.y / _vector4.w;
-					_particle.z = _vector4.z;
-
-					_particle.rotation = object.rotation.z;
-
-					_particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) );
-					_particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) );
-
-					_particle.material = object.material;
-
-					_renderData.elements.push( _particle );
-
-				}
-
-			}
-
-		}
-
-		if ( sortElements === true ) _renderData.elements.sort( painterSort );
-
-		return _renderData;
-
-	};
-
-	// Pools
-
-	function getNextObjectInPool() {
-
-		if ( _objectCount === _objectPoolLength ) {
-
-			var object = new THREE.RenderableObject();
-			_objectPool.push( object );
-			_objectPoolLength ++;
-			_objectCount ++;
-			return object;
-
-		}
-
-		return _objectPool[ _objectCount ++ ];
-
-	}
-
-	function getNextVertexInPool() {
-
-		if ( _vertexCount === _vertexPoolLength ) {
-
-			var vertex = new THREE.RenderableVertex();
-			_vertexPool.push( vertex );
-			_vertexPoolLength ++;
-			_vertexCount ++;
-			return vertex;
-
-		}
-
-		return _vertexPool[ _vertexCount ++ ];
-
-	}
-
-	function getNextFace3InPool() {
-
-		if ( _face3Count === _face3PoolLength ) {
-
-			var face = new THREE.RenderableFace3();
-			_face3Pool.push( face );
-			_face3PoolLength ++;
-			_face3Count ++;
-			return face;
-
-		}
-
-		return _face3Pool[ _face3Count ++ ];
-
-
-	}
-
-	function getNextFace4InPool() {
-
-		if ( _face4Count === _face4PoolLength ) {
-
-			var face = new THREE.RenderableFace4();
-			_face4Pool.push( face );
-			_face4PoolLength ++;
-			_face4Count ++;
-			return face;
-
-		}
-
-		return _face4Pool[ _face4Count ++ ];
-
-	}
-
-	function getNextLineInPool() {
-
-		if ( _lineCount === _linePoolLength ) {
-
-			var line = new THREE.RenderableLine();
-			_linePool.push( line );
-			_linePoolLength ++;
-			_lineCount ++
-			return line;
-
-		}
-
-		return _linePool[ _lineCount ++ ];
-
-	}
-
-	function getNextParticleInPool() {
-
-		if ( _particleCount === _particlePoolLength ) {
-
-			var particle = new THREE.RenderableParticle();
-			_particlePool.push( particle );
-			_particlePoolLength ++;
-			_particleCount ++
-			return particle;
-
-		}
-
-		return _particlePool[ _particleCount ++ ];
-
-	}
-
-	//
-
-	function painterSort( a, b ) {
-
-		return b.z - a.z;
-
-	}
-
-	function clipLine( s1, s2 ) {
-
-		var alpha1 = 0, alpha2 = 1,
-
-		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
-		// Z = -1 and Z = +1, respectively.
-		bc1near =  s1.z + s1.w,
-		bc2near =  s2.z + s2.w,
-		bc1far =  - s1.z + s1.w,
-		bc2far =  - s2.z + s2.w;
-
-		if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
-
-			// Both vertices lie entirely within all clip planes.
-			return true;
-
-		} else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {
-
-			// Both vertices lie entirely outside one of the clip planes.
-			return false;
-
-		} else {
-
-			// The line segment spans at least one clip plane.
-
-			if ( bc1near < 0 ) {
-
-				// v1 lies outside the near plane, v2 inside
-				alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
-
-			} else if ( bc2near < 0 ) {
-
-				// v2 lies outside the near plane, v1 inside
-				alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
-
-			}
-
-			if ( bc1far < 0 ) {
-
-				// v1 lies outside the far plane, v2 inside
-				alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
-
-			} else if ( bc2far < 0 ) {
-
-				// v2 lies outside the far plane, v2 inside
-				alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
-
-			}
-
-			if ( alpha2 < alpha1 ) {
-
-				// The line segment spans two boundaries, but is outside both of them.
-				// (This can't happen when we're only clipping against just near/far but good
-				//  to leave the check here for future usage if other clip planes are added.)
-				return false;
-
-			} else {
-
-				// Update the s1 and s2 vertices to match the clipped line segment.
-				s1.lerp( s2, alpha1 );
-				s2.lerp( s1, 1 - alpha2 );
-
-				return true;
-
-			}
-
-		}
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {
-
-	this.a = a;
-	this.b = b;
-	this.c = c;
-
-	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
-	this.vertexNormals = normal instanceof Array ? normal : [ ];
-
-	this.color = color instanceof THREE.Color ? color : new THREE.Color();
-	this.vertexColors = color instanceof Array ? color : [];
-
-	this.vertexTangents = [];
-
-	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
-
-	this.centroid = new THREE.Vector3();
-
-};
-
-THREE.Face3.prototype = {
-
-	constructor: THREE.Face3,
-
-	clone: function () {
-
-		var face = new THREE.Face3( this.a, this.b, this.c );
-
-		face.normal.copy( this.normal );
-		face.color.copy( this.color );
-		face.centroid.copy( this.centroid );
-
-		face.materialIndex = this.materialIndex;
-
-		var i, il;
-		for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
-		for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
-		for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
-
-		return face;
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {
-
-	this.a = a;
-	this.b = b;
-	this.c = c;
-	this.d = d;
-
-	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
-	this.vertexNormals = normal instanceof Array ? normal : [ ];
-
-	this.color = color instanceof THREE.Color ? color : new THREE.Color();
-	this.vertexColors = color instanceof Array ? color : [];
-
-	this.vertexTangents = [];
-
-	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
-
-	this.centroid = new THREE.Vector3();
-
-};
-
-THREE.Face4.prototype = {
-
-	constructor: THREE.Face4,
-
-	clone: function () {
-
-		var face = new THREE.Face4( this.a, this.b, this.c, this.d );
-
-		face.normal.copy( this.normal );
-		face.color.copy( this.color );
-		face.centroid.copy( this.centroid );
-
-		face.materialIndex = this.materialIndex;
-
-		var i, il;
-		for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
-		for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
-		for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
-
-		return face;
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author kile / http://kile.stravaganza.org/
- * @author alteredq / http://alteredqualia.com/
- * @author mikael emtinger / http://gomo.se/
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author bhouston / http://exocortex.com
- */
-
-THREE.Geometry = function () {
-
-	this.id = THREE.GeometryIdCount ++;
-
-	this.name = '';
-
-	this.vertices = [];
-	this.colors = [];  // one-to-one vertex colors, used in ParticleSystem, Line and Ribbon
-	this.normals = []; // one-to-one vertex normals, used in Ribbon
-
-	this.faces = [];
-
-	this.faceUvs = [[]];
-	this.faceVertexUvs = [[]];
-
-	this.morphTargets = [];
-	this.morphColors = [];
-	this.morphNormals = [];
-
-	this.skinWeights = [];
-	this.skinIndices = [];
-
-	this.lineDistances = [];
-
-	this.boundingBox = null;
-	this.boundingSphere = null;
-
-	this.hasTangents = false;
-
-	this.dynamic = true; // the intermediate typed arrays will be deleted when set to false
-
-	// update flags
-
-	this.verticesNeedUpdate = false;
-	this.elementsNeedUpdate = false;
-	this.uvsNeedUpdate = false;
-	this.normalsNeedUpdate = false;
-	this.tangentsNeedUpdate = false;
-	this.colorsNeedUpdate = false;
-	this.lineDistancesNeedUpdate = false;
-
-	this.buffersNeedUpdate = false;
-
-};
-
-THREE.Geometry.prototype = {
-
-	constructor: THREE.Geometry,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	applyMatrix: function ( matrix ) {
-
-		var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
-
-		for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
-
-			var vertex = this.vertices[ i ];
-			vertex.applyMatrix4( matrix );
-
-		}
-
-		for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
-
-			var face = this.faces[ i ];
-			face.normal.applyMatrix3( normalMatrix ).normalize();
-
-			for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
-
-				face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
-
-			}
-
-			face.centroid.applyMatrix4( matrix );
-
-		}
-
-	},
-
-	computeCentroids: function () {
-
-		var f, fl, face;
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-			face.centroid.set( 0, 0, 0 );
-
-			if ( face instanceof THREE.Face3 ) {
-
-				face.centroid.add( this.vertices[ face.a ] );
-				face.centroid.add( this.vertices[ face.b ] );
-				face.centroid.add( this.vertices[ face.c ] );
-				face.centroid.divideScalar( 3 );
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				face.centroid.add( this.vertices[ face.a ] );
-				face.centroid.add( this.vertices[ face.b ] );
-				face.centroid.add( this.vertices[ face.c ] );
-				face.centroid.add( this.vertices[ face.d ] );
-				face.centroid.divideScalar( 4 );
-
-			}
-
-		}
-
-	},
-
-	computeFaceNormals: function () {
-
-		var cb = new THREE.Vector3(), ab = new THREE.Vector3();
-
-		for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			var face = this.faces[ f ];
-
-			var vA = this.vertices[ face.a ];
-			var vB = this.vertices[ face.b ];
-			var vC = this.vertices[ face.c ];
-
-			cb.subVectors( vC, vB );
-			ab.subVectors( vA, vB );
-			cb.cross( ab );
-
-			cb.normalize();
-
-			face.normal.copy( cb );
-
-		}
-
-	},
-
-	computeVertexNormals: function ( areaWeighted ) {
-
-		var v, vl, f, fl, face, vertices;
-
-		// create internal buffers for reuse when calling this method repeatedly
-		// (otherwise memory allocation / deallocation every frame is big resource hog)
-
-		if ( this.__tmpVertices === undefined ) {
-
-			this.__tmpVertices = new Array( this.vertices.length );
-			vertices = this.__tmpVertices;
-
-			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
-
-				vertices[ v ] = new THREE.Vector3();
-
-			}
-
-			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-				face = this.faces[ f ];
-
-				if ( face instanceof THREE.Face3 ) {
-
-					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-
-				} else if ( face instanceof THREE.Face4 ) {
-
-					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-
-				}
-
-			}
-
-		} else {
-
-			vertices = this.__tmpVertices;
-
-			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
-
-				vertices[ v ].set( 0, 0, 0 );
-
-			}
-
-		}
-
-		if ( areaWeighted ) {
-
-			// vertex normals weighted by triangle areas
-			// http://www.iquilezles.org/www/articles/normals/normals.htm
-
-			var vA, vB, vC, vD;
-			var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
-				db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
-
-			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-				face = this.faces[ f ];
-
-				if ( face instanceof THREE.Face3 ) {
-
-					vA = this.vertices[ face.a ];
-					vB = this.vertices[ face.b ];
-					vC = this.vertices[ face.c ];
-
-					cb.subVectors( vC, vB );
-					ab.subVectors( vA, vB );
-					cb.cross( ab );
-
-					vertices[ face.a ].add( cb );
-					vertices[ face.b ].add( cb );
-					vertices[ face.c ].add( cb );
-
-				} else if ( face instanceof THREE.Face4 ) {
-
-					vA = this.vertices[ face.a ];
-					vB = this.vertices[ face.b ];
-					vC = this.vertices[ face.c ];
-					vD = this.vertices[ face.d ];
-
-					// abd
-
-					db.subVectors( vD, vB );
-					ab.subVectors( vA, vB );
-					db.cross( ab );
-
-					vertices[ face.a ].add( db );
-					vertices[ face.b ].add( db );
-					vertices[ face.d ].add( db );
-
-					// bcd
-
-					dc.subVectors( vD, vC );
-					bc.subVectors( vB, vC );
-					dc.cross( bc );
-
-					vertices[ face.b ].add( dc );
-					vertices[ face.c ].add( dc );
-					vertices[ face.d ].add( dc );
-
-				}
-
-			}
-
-		} else {
-
-			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-				face = this.faces[ f ];
-
-				if ( face instanceof THREE.Face3 ) {
-
-					vertices[ face.a ].add( face.normal );
-					vertices[ face.b ].add( face.normal );
-					vertices[ face.c ].add( face.normal );
-
-				} else if ( face instanceof THREE.Face4 ) {
-
-					vertices[ face.a ].add( face.normal );
-					vertices[ face.b ].add( face.normal );
-					vertices[ face.c ].add( face.normal );
-					vertices[ face.d ].add( face.normal );
-
-				}
-
-			}
-
-		}
-
-		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
-
-			vertices[ v ].normalize();
-
-		}
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-
-			if ( face instanceof THREE.Face3 ) {
-
-				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
-				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
-				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
-				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
-				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
-				face.vertexNormals[ 3 ].copy( vertices[ face.d ] );
-
-			}
-
-		}
-
-	},
-
-	computeMorphNormals: function () {
-
-		var i, il, f, fl, face;
-
-		// save original normals
-		// - create temp variables on first access
-		//   otherwise just copy (for faster repeated calls)
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-
-			if ( ! face.__originalFaceNormal ) {
-
-				face.__originalFaceNormal = face.normal.clone();
-
-			} else {
-
-				face.__originalFaceNormal.copy( face.normal );
-
-			}
-
-			if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
-
-			for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
-
-				if ( ! face.__originalVertexNormals[ i ] ) {
-
-					face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
-
-				} else {
-
-					face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
-
-				}
-
-			}
-
-		}
-
-		// use temp geometry to compute face and vertex normals for each morph
-
-		var tmpGeo = new THREE.Geometry();
-		tmpGeo.faces = this.faces;
-
-		for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
-
-			// create on first access
-
-			if ( ! this.morphNormals[ i ] ) {
-
-				this.morphNormals[ i ] = {};
-				this.morphNormals[ i ].faceNormals = [];
-				this.morphNormals[ i ].vertexNormals = [];
-
-				var dstNormalsFace = this.morphNormals[ i ].faceNormals;
-				var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
-
-				var faceNormal, vertexNormals;
-
-				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-					face = this.faces[ f ];
-
-					faceNormal = new THREE.Vector3();
-
-					if ( face instanceof THREE.Face3 ) {
-
-						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
-
-					} else {
-
-						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3(), d: new THREE.Vector3() };
-
-					}
-
-					dstNormalsFace.push( faceNormal );
-					dstNormalsVertex.push( vertexNormals );
-
-				}
-
-			}
-
-			var morphNormals = this.morphNormals[ i ];
-
-			// set vertices to morph target
-
-			tmpGeo.vertices = this.morphTargets[ i ].vertices;
-
-			// compute morph normals
-
-			tmpGeo.computeFaceNormals();
-			tmpGeo.computeVertexNormals();
-
-			// store morph normals
-
-			var faceNormal, vertexNormals;
-
-			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-				face = this.faces[ f ];
-
-				faceNormal = morphNormals.faceNormals[ f ];
-				vertexNormals = morphNormals.vertexNormals[ f ];
-
-				faceNormal.copy( face.normal );
-
-				if ( face instanceof THREE.Face3 ) {
-
-					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
-					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
-					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
-
-				} else {
-
-					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
-					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
-					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
-					vertexNormals.d.copy( face.vertexNormals[ 3 ] );
-
-				}
-
-			}
-
-		}
-
-		// restore original normals
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-
-			face.normal = face.__originalFaceNormal;
-			face.vertexNormals = face.__originalVertexNormals;
-
-		}
-
-	},
-
-	computeTangents: function () {
-
-		// based on http://www.terathon.com/code/tangent.html
-		// tangents go to vertices
-
-		var f, fl, v, vl, i, il, vertexIndex,
-			face, uv, vA, vB, vC, uvA, uvB, uvC,
-			x1, x2, y1, y2, z1, z2,
-			s1, s2, t1, t2, r, t, test,
-			tan1 = [], tan2 = [],
-			sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
-			tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
-			n = new THREE.Vector3(), w;
-
-		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
-
-			tan1[ v ] = new THREE.Vector3();
-			tan2[ v ] = new THREE.Vector3();
-
-		}
-
-		function handleTriangle( context, a, b, c, ua, ub, uc ) {
-
-			vA = context.vertices[ a ];
-			vB = context.vertices[ b ];
-			vC = context.vertices[ c ];
-
-			uvA = uv[ ua ];
-			uvB = uv[ ub ];
-			uvC = uv[ uc ];
-
-			x1 = vB.x - vA.x;
-			x2 = vC.x - vA.x;
-			y1 = vB.y - vA.y;
-			y2 = vC.y - vA.y;
-			z1 = vB.z - vA.z;
-			z2 = vC.z - vA.z;
-
-			s1 = uvB.x - uvA.x;
-			s2 = uvC.x - uvA.x;
-			t1 = uvB.y - uvA.y;
-			t2 = uvC.y - uvA.y;
-
-			r = 1.0 / ( s1 * t2 - s2 * t1 );
-			sdir.set( ( t2 * x1 - t1 * x2 ) * r,
-					  ( t2 * y1 - t1 * y2 ) * r,
-					  ( t2 * z1 - t1 * z2 ) * r );
-			tdir.set( ( s1 * x2 - s2 * x1 ) * r,
-					  ( s1 * y2 - s2 * y1 ) * r,
-					  ( s1 * z2 - s2 * z1 ) * r );
-
-			tan1[ a ].add( sdir );
-			tan1[ b ].add( sdir );
-			tan1[ c ].add( sdir );
-
-			tan2[ a ].add( tdir );
-			tan2[ b ].add( tdir );
-			tan2[ c ].add( tdir );
-
-		}
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-			uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents
-
-			if ( face instanceof THREE.Face3 ) {
-
-				handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 );
-				handleTriangle( this, face.b, face.c, face.d, 1, 2, 3 );
-
-			}
-
-		}
-
-		var faceIndex = [ 'a', 'b', 'c', 'd' ];
-
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
-			face = this.faces[ f ];
-
-			for ( i = 0; i < face.vertexNormals.length; i++ ) {
-
-				n.copy( face.vertexNormals[ i ] );
-
-				vertexIndex = face[ faceIndex[ i ] ];
-
-				t = tan1[ vertexIndex ];
-
-				// Gram-Schmidt orthogonalize
-
-				tmp.copy( t );
-				tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
-
-				// Calculate handedness
-
-				tmp2.crossVectors( face.vertexNormals[ i ], t );
-				test = tmp2.dot( tan2[ vertexIndex ] );
-				w = (test < 0.0) ? -1.0 : 1.0;
-
-				face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );
-
-			}
-
-		}
-
-		this.hasTangents = true;
-
-	},
-
-	computeLineDistances: function ( ) {
-
-		var d = 0;
-		var vertices = this.vertices;
-
-		for ( var i = 0, il = vertices.length; i < il; i ++ ) {
-
-			if ( i > 0 ) {
-
-				d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
-
-			}
-
-			this.lineDistances[ i ] = d;
-
-		}
-
-	},
-
-	computeBoundingBox: function () {
-
-		if ( this.boundingBox === null ) {
-
-			this.boundingBox = new THREE.Box3();
-
-		}
-
-		this.boundingBox.setFromPoints( this.vertices );
-
-	},
-
-	computeBoundingSphere: function () {
-
-		if ( this.boundingSphere === null ) {
-
-			this.boundingSphere = new THREE.Sphere();
-
-		}
-
-		this.boundingSphere.setFromCenterAndPoints( this.boundingSphere.center, this.vertices );
-
-	},
-
-	/*
-	 * Checks for duplicate vertices with hashmap.
-	 * Duplicated vertices are removed
-	 * and faces' vertices are updated.
-	 */
-
-	mergeVertices: function () {
-
-		var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)
-		var unique = [], changes = [];
-
-		var v, key;
-		var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001
-		var precision = Math.pow( 10, precisionPoints );
-		var i,il, face;
-		var indices, k, j, jl, u;
-
-		// reset cache of vertices as it now will be changing.
-		this.__tmpVertices = undefined;
-
-		for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
-
-			v = this.vertices[ i ];
-			key = [ Math.round( v.x * precision ), Math.round( v.y * precision ), Math.round( v.z * precision ) ].join( '_' );
-
-			if ( verticesMap[ key ] === undefined ) {
-
-				verticesMap[ key ] = i;
-				unique.push( this.vertices[ i ] );
-				changes[ i ] = unique.length - 1;
-
-			} else {
-
-				//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
-				changes[ i ] = changes[ verticesMap[ key ] ];
-
-			}
-
-		};
-
-
-		// if faces are completely degenerate after merging vertices, we
-		// have to remove them from the geometry.
-		var faceIndicesToRemove = [];
-
-		for( i = 0, il = this.faces.length; i < il; i ++ ) {
-
-			face = this.faces[ i ];
-
-			if ( face instanceof THREE.Face3 ) {
-
-				face.a = changes[ face.a ];
-				face.b = changes[ face.b ];
-				face.c = changes[ face.c ];
-
-				indices = [ face.a, face.b, face.c ];
-
-				var dupIndex = -1;
-
-				// if any duplicate vertices are found in a Face3
-				// we have to remove the face as nothing can be saved
-				for ( var n = 0; n < 3; n ++ ) {
-					if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) {
-
-						dupIndex = n;
-						faceIndicesToRemove.push( i );
-						break;
-
-					}
-				}
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				face.a = changes[ face.a ];
-				face.b = changes[ face.b ];
-				face.c = changes[ face.c ];
-				face.d = changes[ face.d ];
-
-				// check dups in (a, b, c, d) and convert to -> face3
-
-				indices = [ face.a, face.b, face.c, face.d ];
-
-				var dupIndex = -1;
-
-				for ( var n = 0; n < 4; n ++ ) {
-
-					if ( indices[ n ] == indices[ ( n + 1 ) % 4 ] ) {
-
-						// if more than one duplicated vertex is found
-						// we can't generate any valid Face3's, thus
-						// we need to remove this face complete.
-						if ( dupIndex >= 0 ) {
-
-							faceIndicesToRemove.push( i );
-
-						}
-
-						dupIndex = n;
-
-					}
-				}
-
-				if ( dupIndex >= 0 ) {
-
-					indices.splice( dupIndex, 1 );
-
-					var newFace = new THREE.Face3( indices[0], indices[1], indices[2], face.normal, face.color, face.materialIndex );
-
-					for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
-
-						u = this.faceVertexUvs[ j ][ i ];
-
-						if ( u ) {
-							u.splice( dupIndex, 1 );
-						}
-
-					}
-
-					if( face.vertexNormals && face.vertexNormals.length > 0) {
-
-						newFace.vertexNormals = face.vertexNormals;
-						newFace.vertexNormals.splice( dupIndex, 1 );
-
-					}
-
-					if( face.vertexColors && face.vertexColors.length > 0 ) {
-
-						newFace.vertexColors = face.vertexColors;
-						newFace.vertexColors.splice( dupIndex, 1 );
-					}
-
-					this.faces[ i ] = newFace;
-				}
-
-			}
-
-		}
-
-		for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
-
-			this.faces.splice( i, 1 );
-
-			for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
-
-				this.faceVertexUvs[ j ].splice( i, 1 );
-
-			}
-
-		}
-
-		// Use unique set of vertices
-
-		var diff = this.vertices.length - unique.length;
-		this.vertices = unique;
-		return diff;
-
-	},
-
-	clone: function () {
-
-		var geometry = new THREE.Geometry();
-
-		var vertices = this.vertices;
-
-		for ( var i = 0, il = vertices.length; i < il; i ++ ) {
-
-			geometry.vertices.push( vertices[ i ].clone() );
-
-		}
-
-		var faces = this.faces;
-
-		for ( var i = 0, il = faces.length; i < il; i ++ ) {
-
-			geometry.faces.push( faces[ i ].clone() );
-
-		}
-
-		var uvs = this.faceVertexUvs[ 0 ];
-
-		for ( var i = 0, il = uvs.length; i < il; i ++ ) {
-
-			var uv = uvs[ i ], uvCopy = [];
-
-			for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
-
-				uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
-
-			}
-
-			geometry.faceVertexUvs[ 0 ].push( uvCopy );
-
-		}
-
-		return geometry;
-
-	},
-
-	dispose: function () {
-
-		this.dispatchEvent( { type: 'dispose' } );
-
-	}
-
-};
-
-THREE.GeometryIdCount = 0;
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.BufferGeometry = function () {
-
-	this.id = THREE.GeometryIdCount ++;
-
-	// attributes
-
-	this.attributes = {};
-
-	// attributes typed arrays are kept only if dynamic flag is set
-
-	this.dynamic = false;
-
-	// offsets for chunks when using indexed elements
-
-	this.offsets = [];
-
-	// boundings
-
-	this.boundingBox = null;
-	this.boundingSphere = null;
-
-	this.hasTangents = false;
-
-	// for compatibility
-
-	this.morphTargets = [];
-
-};
-
-THREE.BufferGeometry.prototype = {
-
-	constructor: THREE.BufferGeometry,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	applyMatrix: function ( matrix ) {
-
-		var positionArray;
-		var normalArray;
-
-		if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array;
-		if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array;
-
-		if ( positionArray !== undefined ) {
-
-			matrix.multiplyVector3Array( positionArray );
-			this.verticesNeedUpdate = true;
-
-		}
-
-		if ( normalArray !== undefined ) {
-
-			var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
-
-			normalMatrix.multiplyVector3Array( normalArray );
-
-			this.normalizeNormals();
-
-			this.normalsNeedUpdate = true;
-
-		}
-
-	},
-
-	computeBoundingBox: function () {
-
-		if ( this.boundingBox === null ) {
-
-			this.boundingBox = new THREE.Box3();
-
-		}
-
-		var positions = this.attributes[ "position" ].array;
-
-		if ( positions ) {
-
-			var bb = this.boundingBox;
-			var x, y, z;
-
-			if( positions.length >= 3 ) {
-				bb.min.x = bb.max.x = positions[ 0 ];
-				bb.min.y = bb.max.y = positions[ 1 ];
-				bb.min.z = bb.max.z = positions[ 2 ];
-			}
-
-			for ( var i = 3, il = positions.length; i < il; i += 3 ) {
-
-				x = positions[ i ];
-				y = positions[ i + 1 ];
-				z = positions[ i + 2 ];
-
-				// bounding box
-
-				if ( x < bb.min.x ) {
-
-					bb.min.x = x;
-
-				} else if ( x > bb.max.x ) {
-
-					bb.max.x = x;
-
-				}
-
-				if ( y < bb.min.y ) {
-
-					bb.min.y = y;
-
-				} else if ( y > bb.max.y ) {
-
-					bb.max.y = y;
-
-				}
-
-				if ( z < bb.min.z ) {
-
-					bb.min.z = z;
-
-				} else if ( z > bb.max.z ) {
-
-					bb.max.z = z;
-
-				}
-
-			}
-
-		}
-
-		if ( positions === undefined || positions.length === 0 ) {
-
-			this.boundingBox.min.set( 0, 0, 0 );
-			this.boundingBox.max.set( 0, 0, 0 );
-
-		}
-
-	},
-
-	computeBoundingSphere: function () {
-
-		if ( this.boundingSphere === null ) {
-
-			this.boundingSphere = new THREE.Sphere();
-
-		}
-
-		var positions = this.attributes[ "position" ].array;
-
-		if ( positions ) {
-
-			var radiusSq, maxRadiusSq = 0;
-			var x, y, z;
-
-			for ( var i = 0, il = positions.length; i < il; i += 3 ) {
-
-				x = positions[ i ];
-				y = positions[ i + 1 ];
-				z = positions[ i + 2 ];
-
-				radiusSq =  x * x + y * y + z * z;
-				if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq;
-
-			}
-
-			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
-
-		}
-
-	},
-
-	computeVertexNormals: function () {
-
-		if ( this.attributes[ "position" ] ) {
-
-			var i, il;
-			var j, jl;
-
-			var nVertexElements = this.attributes[ "position" ].array.length;
-
-			if ( this.attributes[ "normal" ] === undefined ) {
-
-				this.attributes[ "normal" ] = {
-
-					itemSize: 3,
-					array: new Float32Array( nVertexElements ),
-					numItems: nVertexElements
-
-				};
-
-			} else {
-
-				// reset existing normals to zero
-
-				for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) {
-
-					this.attributes[ "normal" ].array[ i ] = 0;
-
-				}
-
-			}
-
-			var positions = this.attributes[ "position" ].array;
-			var normals = this.attributes[ "normal" ].array;
-
-			var vA, vB, vC, x, y, z,
-
-			pA = new THREE.Vector3(),
-			pB = new THREE.Vector3(),
-			pC = new THREE.Vector3(),
-
-			cb = new THREE.Vector3(),
-			ab = new THREE.Vector3();
-
-			// indexed elements
-
-			if ( this.attributes[ "index" ] ) {
-
-				var indices = this.attributes[ "index" ].array;
-
-				var offsets = this.offsets;
-
-				for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
-
-					var start = offsets[ j ].start;
-					var count = offsets[ j ].count;
-					var index = offsets[ j ].index;
-
-					for ( i = start, il = start + count; i < il; i += 3 ) {
-
-						vA = index + indices[ i ];
-						vB = index + indices[ i + 1 ];
-						vC = index + indices[ i + 2 ];
-
-						x = positions[ vA * 3 ];
-						y = positions[ vA * 3 + 1 ];
-						z = positions[ vA * 3 + 2 ];
-						pA.set( x, y, z );
-
-						x = positions[ vB * 3 ];
-						y = positions[ vB * 3 + 1 ];
-						z = positions[ vB * 3 + 2 ];
-						pB.set( x, y, z );
-
-						x = positions[ vC * 3 ];
-						y = positions[ vC * 3 + 1 ];
-						z = positions[ vC * 3 + 2 ];
-						pC.set( x, y, z );
-
-						cb.subVectors( pC, pB );
-						ab.subVectors( pA, pB );
-						cb.cross( ab );
-
-						normals[ vA * 3 ]     += cb.x;
-						normals[ vA * 3 + 1 ] += cb.y;
-						normals[ vA * 3 + 2 ] += cb.z;
-
-						normals[ vB * 3 ]     += cb.x;
-						normals[ vB * 3 + 1 ] += cb.y;
-						normals[ vB * 3 + 2 ] += cb.z;
-
-						normals[ vC * 3 ]     += cb.x;
-						normals[ vC * 3 + 1 ] += cb.y;
-						normals[ vC * 3 + 2 ] += cb.z;
-
-					}
-
-				}
-
-			// non-indexed elements (unconnected triangle soup)
-
-			} else {
-
-				for ( i = 0, il = positions.length; i < il; i += 9 ) {
-
-					x = positions[ i ];
-					y = positions[ i + 1 ];
-					z = positions[ i + 2 ];
-					pA.set( x, y, z );
-
-					x = positions[ i + 3 ];
-					y = positions[ i + 4 ];
-					z = positions[ i + 5 ];
-					pB.set( x, y, z );
-
-					x = positions[ i + 6 ];
-					y = positions[ i + 7 ];
-					z = positions[ i + 8 ];
-					pC.set( x, y, z );
-
-					cb.subVectors( pC, pB );
-					ab.subVectors( pA, pB );
-					cb.cross( ab );
-
-					normals[ i ] 	 = cb.x;
-					normals[ i + 1 ] = cb.y;
-					normals[ i + 2 ] = cb.z;
-
-					normals[ i + 3 ] = cb.x;
-					normals[ i + 4 ] = cb.y;
-					normals[ i + 5 ] = cb.z;
-
-					normals[ i + 6 ] = cb.x;
-					normals[ i + 7 ] = cb.y;
-					normals[ i + 8 ] = cb.z;
-
-				}
-
-			}
-
-			this.normalizeNormals();
-
-			this.normalsNeedUpdate = true;
-
-		}
-
-	},
-
-	normalizeNormals: function () {
-
-		var normals = this.attributes[ "normal" ].array;
-
-		var x, y, z, n;
-
-		for ( var i = 0, il = normals.length; i < il; i += 3 ) {
-
-			x = normals[ i ];
-			y = normals[ i + 1 ];
-			z = normals[ i + 2 ];
-
-			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
-
-			normals[ i ] 	 *= n;
-			normals[ i + 1 ] *= n;
-			normals[ i + 2 ] *= n;
-
-		}
-
-	},
-
-	computeTangents: function () {
-
-		// based on http://www.terathon.com/code/tangent.html
-		// (per vertex tangents)
-
-		if ( this.attributes[ "index" ] === undefined ||
-			 this.attributes[ "position" ] === undefined ||
-			 this.attributes[ "normal" ] === undefined ||
-			 this.attributes[ "uv" ] === undefined ) {
-
-			console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" );
-			return;
-
-		}
-
-		var indices = this.attributes[ "index" ].array;
-		var positions = this.attributes[ "position" ].array;
-		var normals = this.attributes[ "normal" ].array;
-		var uvs = this.attributes[ "uv" ].array;
-
-		var nVertices = positions.length / 3;
-
-		if ( this.attributes[ "tangent" ] === undefined ) {
-
-			var nTangentElements = 4 * nVertices;
-
-			this.attributes[ "tangent" ] = {
-
-				itemSize: 4,
-				array: new Float32Array( nTangentElements ),
-				numItems: nTangentElements
-
-			};
-
-		}
-
-		var tangents = this.attributes[ "tangent" ].array;
-
-		var tan1 = [], tan2 = [];
-
-		for ( var k = 0; k < nVertices; k ++ ) {
-
-			tan1[ k ] = new THREE.Vector3();
-			tan2[ k ] = new THREE.Vector3();
-
-		}
-
-		var xA, yA, zA,
-			xB, yB, zB,
-			xC, yC, zC,
-
-			uA, vA,
-			uB, vB,
-			uC, vC,
-
-			x1, x2, y1, y2, z1, z2,
-			s1, s2, t1, t2, r;
-
-		var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
-
-		function handleTriangle( a, b, c ) {
-
-			xA = positions[ a * 3 ];
-			yA = positions[ a * 3 + 1 ];
-			zA = positions[ a * 3 + 2 ];
-
-			xB = positions[ b * 3 ];
-			yB = positions[ b * 3 + 1 ];
-			zB = positions[ b * 3 + 2 ];
-
-			xC = positions[ c * 3 ];
-			yC = positions[ c * 3 + 1 ];
-			zC = positions[ c * 3 + 2 ];
-
-			uA = uvs[ a * 2 ];
-			vA = uvs[ a * 2 + 1 ];
-
-			uB = uvs[ b * 2 ];
-			vB = uvs[ b * 2 + 1 ];
-
-			uC = uvs[ c * 2 ];
-			vC = uvs[ c * 2 + 1 ];
-
-			x1 = xB - xA;
-			x2 = xC - xA;
-
-			y1 = yB - yA;
-			y2 = yC - yA;
-
-			z1 = zB - zA;
-			z2 = zC - zA;
-
-			s1 = uB - uA;
-			s2 = uC - uA;
-
-			t1 = vB - vA;
-			t2 = vC - vA;
-
-			r = 1.0 / ( s1 * t2 - s2 * t1 );
-
-			sdir.set(
-				( t2 * x1 - t1 * x2 ) * r,
-				( t2 * y1 - t1 * y2 ) * r,
-				( t2 * z1 - t1 * z2 ) * r
-			);
-
-			tdir.set(
-				( s1 * x2 - s2 * x1 ) * r,
-				( s1 * y2 - s2 * y1 ) * r,
-				( s1 * z2 - s2 * z1 ) * r
-			);
-
-			tan1[ a ].add( sdir );
-			tan1[ b ].add( sdir );
-			tan1[ c ].add( sdir );
-
-			tan2[ a ].add( tdir );
-			tan2[ b ].add( tdir );
-			tan2[ c ].add( tdir );
-
-		}
-
-		var i, il;
-		var j, jl;
-		var iA, iB, iC;
-
-		var offsets = this.offsets;
-
-		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
-
-			var start = offsets[ j ].start;
-			var count = offsets[ j ].count;
-			var index = offsets[ j ].index;
-
-			for ( i = start, il = start + count; i < il; i += 3 ) {
-
-				iA = index + indices[ i ];
-				iB = index + indices[ i + 1 ];
-				iC = index + indices[ i + 2 ];
-
-				handleTriangle( iA, iB, iC );
-
-			}
-
-		}
-
-		var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
-		var n = new THREE.Vector3(), n2 = new THREE.Vector3();
-		var w, t, test;
-
-		function handleVertex( v ) {
-
-			n.x = normals[ v * 3 ];
-			n.y = normals[ v * 3 + 1 ];
-			n.z = normals[ v * 3 + 2 ];
-
-			n2.copy( n );
-
-			t = tan1[ v ];
-
-			// Gram-Schmidt orthogonalize
-
-			tmp.copy( t );
-			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
-
-			// Calculate handedness
-
-			tmp2.crossVectors( n2, t );
-			test = tmp2.dot( tan2[ v ] );
-			w = ( test < 0.0 ) ? -1.0 : 1.0;
-
-			tangents[ v * 4 ]     = tmp.x;
-			tangents[ v * 4 + 1 ] = tmp.y;
-			tangents[ v * 4 + 2 ] = tmp.z;
-			tangents[ v * 4 + 3 ] = w;
-
-		}
-
-		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
-
-			var start = offsets[ j ].start;
-			var count = offsets[ j ].count;
-			var index = offsets[ j ].index;
-
-			for ( i = start, il = start + count; i < il; i += 3 ) {
-
-				iA = index + indices[ i ];
-				iB = index + indices[ i + 1 ];
-				iC = index + indices[ i + 2 ];
-
-				handleVertex( iA );
-				handleVertex( iB );
-				handleVertex( iC );
-
-			}
-
-		}
-
-		this.hasTangents = true;
-		this.tangentsNeedUpdate = true;
-
-	},
-
-	dispose: function () {
-
-		this.dispatchEvent( { type: 'dispose' } );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author mikael emtinger / http://gomo.se/
- * @author WestLangley / http://github.com/WestLangley
-*/
-
-THREE.Camera = function () {
-
-	THREE.Object3D.call( this );
-
-	this.matrixWorldInverse = new THREE.Matrix4();
-
-	this.projectionMatrix = new THREE.Matrix4();
-	this.projectionMatrixInverse = new THREE.Matrix4();
-
-};
-
-THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Camera.prototype.lookAt = function () {
-
-	// This routine does not support cameras with rotated and/or translated parent(s)
-
-	var m1 = new THREE.Matrix4();
-
-	return function ( vector ) {
-
-		m1.lookAt( this.position, vector, this.up );
-
-		if ( this.useQuaternion === true )  {
-
-			this.quaternion.setFromRotationMatrix( m1 );
-
-		} else {
-
-			this.rotation.setEulerFromRotationMatrix( m1, this.eulerOrder );
-
-		}
-
-	};
-
-}();
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {
-
-	THREE.Camera.call( this );
-
-	this.left = left;
-	this.right = right;
-	this.top = top;
-	this.bottom = bottom;
-
-	this.near = ( near !== undefined ) ? near : 0.1;
-	this.far = ( far !== undefined ) ? far : 2000;
-
-	this.updateProjectionMatrix();
-
-};
-
-THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype );
-
-THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {
-
-	this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author greggman / http://games.greggman.com/
- * @author zz85 / http://www.lab4games.net/zz85/blog
- */
-
-THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
-
-	THREE.Camera.call( this );
-
-	this.fov = fov !== undefined ? fov : 50;
-	this.aspect = aspect !== undefined ? aspect : 1;
-	this.near = near !== undefined ? near : 0.1;
-	this.far = far !== undefined ? far : 2000;
-
-	this.updateProjectionMatrix();
-
-};
-
-THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );
-
-
-/**
- * Uses Focal Length (in mm) to estimate and set FOV
- * 35mm (fullframe) camera is used if frame size is not specified;
- * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
- */
-
-THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
-
-	if ( frameHeight === undefined ) frameHeight = 24;
-
-	this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
-	this.updateProjectionMatrix();
-
-}
-
-
-/**
- * Sets an offset in a larger frustum. This is useful for multi-window or
- * multi-monitor/multi-machine setups.
- *
- * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
- * the monitors are in grid like this
- *
- *   +---+---+---+
- *   | A | B | C |
- *   +---+---+---+
- *   | D | E | F |
- *   +---+---+---+
- *
- * then for each monitor you would call it like this
- *
- *   var w = 1920;
- *   var h = 1080;
- *   var fullWidth = w * 3;
- *   var fullHeight = h * 2;
- *
- *   --A--
- *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
- *   --B--
- *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
- *   --C--
- *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
- *   --D--
- *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
- *   --E--
- *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
- *   --F--
- *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
- *
- *   Note there is no reason monitors have to be the same size or in a grid.
- */
-
-THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {
-
-	this.fullWidth = fullWidth;
-	this.fullHeight = fullHeight;
-	this.x = x;
-	this.y = y;
-	this.width = width;
-	this.height = height;
-
-	this.updateProjectionMatrix();
-
-};
-
-
-THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {
-
-	if ( this.fullWidth ) {
-
-		var aspect = this.fullWidth / this.fullHeight;
-		var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near;
-		var bottom = -top;
-		var left = aspect * bottom;
-		var right = aspect * top;
-		var width = Math.abs( right - left );
-		var height = Math.abs( top - bottom );
-
-		this.projectionMatrix.makeFrustum(
-			left + this.x * width / this.fullWidth,
-			left + ( this.x + this.width ) * width / this.fullWidth,
-			top - ( this.y + this.height ) * height / this.fullHeight,
-			top - this.y * height / this.fullHeight,
-			this.near,
-			this.far
-		);
-
-	} else {
-
-		this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
- 
-THREE.Light = function ( hex ) {
-
-	THREE.Object3D.call( this );
-
-	this.color = new THREE.Color( hex );
-
-};
-
-THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Light.prototype.clone = function ( light ) {
-
-	if ( light === undefined ) light = new THREE.Light();
-
-	THREE.Object3D.prototype.clone.call( this, light );
-
-	light.color.copy( this.color );
-
-	return light;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.AmbientLight = function ( hex ) {
-
-	THREE.Light.call( this, hex );
-
-};
-
-THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
-
-THREE.AmbientLight.prototype.clone = function () {
-
-	var light = new THREE.AmbientLight();
-
-	THREE.Light.prototype.clone.call( this, light );
-
-	return light;
-
-};
-/**
- * @author MPanknin / http://www.redplant.de/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.AreaLight = function ( hex, intensity ) {
-
-	THREE.Light.call( this, hex );
-
-	this.normal = new THREE.Vector3( 0, -1, 0 );
-	this.right = new THREE.Vector3( 1, 0, 0 );
-
-	this.intensity = ( intensity !== undefined ) ? intensity : 1;
-
-	this.width = 1.0;
-	this.height = 1.0;
-
-	this.constantAttenuation = 1.5;
-	this.linearAttenuation = 0.5;
-	this.quadraticAttenuation = 0.1;
-
-};
-
-THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
-
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.DirectionalLight = function ( hex, intensity ) {
-
-	THREE.Light.call( this, hex );
-
-	this.position.set( 0, 1, 0 );
-	this.target = new THREE.Object3D();
-
-	this.intensity = ( intensity !== undefined ) ? intensity : 1;
-
-	this.castShadow = false;
-	this.onlyShadow = false;
-
-	//
-
-	this.shadowCameraNear = 50;
-	this.shadowCameraFar = 5000;
-
-	this.shadowCameraLeft = -500;
-	this.shadowCameraRight = 500;
-	this.shadowCameraTop = 500;
-	this.shadowCameraBottom = -500;
-
-	this.shadowCameraVisible = false;
-
-	this.shadowBias = 0;
-	this.shadowDarkness = 0.5;
-
-	this.shadowMapWidth = 512;
-	this.shadowMapHeight = 512;
-
-	//
-
-	this.shadowCascade = false;
-
-	this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 );
-	this.shadowCascadeCount = 2;
-
-	this.shadowCascadeBias = [ 0, 0, 0 ];
-	this.shadowCascadeWidth = [ 512, 512, 512 ];
-	this.shadowCascadeHeight = [ 512, 512, 512 ];
-
-	this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ];
-	this.shadowCascadeFarZ  = [  0.990, 0.998, 1.000 ];
-
-	this.shadowCascadeArray = [];
-
-	//
-
-	this.shadowMap = null;
-	this.shadowMapSize = null;
-	this.shadowCamera = null;
-	this.shadowMatrix = null;
-
-};
-
-THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );
-
-THREE.DirectionalLight.prototype.clone = function () {
-
-	var light = new THREE.DirectionalLight();
-
-	THREE.Light.prototype.clone.call( this, light );
-
-	light.target = this.target.clone();
-
-	light.intensity = this.intensity;
-
-	light.castShadow = this.castShadow;
-	light.onlyShadow = this.onlyShadow;
-
-	return light;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.HemisphereLight = function ( skyColorHex, groundColorHex, intensity ) {
-
-	THREE.Light.call( this, skyColorHex );
-
-	this.position.set( 0, 100, 0 );
-
-	this.groundColor = new THREE.Color( groundColorHex );
-	this.intensity = ( intensity !== undefined ) ? intensity : 1;
-
-};
-
-THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
-
-THREE.HemisphereLight.prototype.clone = function () {
-
-	var light = new THREE.PointLight();
-
-	THREE.Light.prototype.clone.call( this, light );
-
-	light.groundColor.copy( this.groundColor );
-	light.intensity = this.intensity;
-
-	return light;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.PointLight = function ( hex, intensity, distance ) {
-
-	THREE.Light.call( this, hex );
-
-	this.intensity = ( intensity !== undefined ) ? intensity : 1;
-	this.distance = ( distance !== undefined ) ? distance : 0;
-
-};
-
-THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
-
-THREE.PointLight.prototype.clone = function () {
-
-	var light = new THREE.PointLight();
-
-	THREE.Light.prototype.clone.call( this, light );
-
-	light.intensity = this.intensity;
-	light.distance = this.distance;
-
-	return light;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) {
-
-	THREE.Light.call( this, hex );
-
-	this.position.set( 0, 1, 0 );
-	this.target = new THREE.Object3D();
-
-	this.intensity = ( intensity !== undefined ) ? intensity : 1;
-	this.distance = ( distance !== undefined ) ? distance : 0;
-	this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
-	this.exponent = ( exponent !== undefined ) ? exponent : 10;
-
-	this.castShadow = false;
-	this.onlyShadow = false;
-
-	//
-
-	this.shadowCameraNear = 50;
-	this.shadowCameraFar = 5000;
-	this.shadowCameraFov = 50;
-
-	this.shadowCameraVisible = false;
-
-	this.shadowBias = 0;
-	this.shadowDarkness = 0.5;
-
-	this.shadowMapWidth = 512;
-	this.shadowMapHeight = 512;
-
-	//
-
-	this.shadowMap = null;
-	this.shadowMapSize = null;
-	this.shadowCamera = null;
-	this.shadowMatrix = null;
-
-};
-
-THREE.SpotLight.prototype = Object.create( THREE.Light.prototype );
-
-THREE.SpotLight.prototype.clone = function () {
-
-	var light = new THREE.SpotLight();
-
-	THREE.Light.prototype.clone.call( this, light );
-
-	light.target = this.target.clone();
-
-	light.intensity = this.intensity;
-	light.distance = this.distance;
-	light.angle = this.angle;
-	light.exponent = this.exponent;
-
-	light.castShadow = this.castShadow;
-	light.onlyShadow = this.onlyShadow;
-
-	return light;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Loader = function ( showStatus ) {
-
-	this.showStatus = showStatus;
-	this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;
-
-	this.onLoadStart = function () {};
-	this.onLoadProgress = function () {};
-	this.onLoadComplete = function () {};
-
-};
-
-THREE.Loader.prototype = {
-
-	constructor: THREE.Loader,
-
-	crossOrigin: 'anonymous',
-
-	addStatusElement: function () {
-
-		var e = document.createElement( "div" );
-
-		e.style.position = "absolute";
-		e.style.right = "0px";
-		e.style.top = "0px";
-		e.style.fontSize = "0.8em";
-		e.style.textAlign = "left";
-		e.style.background = "rgba(0,0,0,0.25)";
-		e.style.color = "#fff";
-		e.style.width = "120px";
-		e.style.padding = "0.5em 0.5em 0.5em 0.5em";
-		e.style.zIndex = 1000;
-
-		e.innerHTML = "Loading ...";
-
-		return e;
-
-	},
-
-	updateProgress: function ( progress ) {
-
-		var message = "Loaded ";
-
-		if ( progress.total ) {
-
-			message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%";
-
-
-		} else {
-
-			message += ( progress.loaded / 1000 ).toFixed(2) + " KB";
-
-		}
-
-		this.statusDomElement.innerHTML = message;
-
-	},
-
-	extractUrlBase: function ( url ) {
-
-		var parts = url.split( '/' );
-		parts.pop();
-		return ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
-
-	},
-
-	initMaterials: function ( materials, texturePath ) {
-
-		var array = [];
-
-		for ( var i = 0; i < materials.length; ++ i ) {
-
-			array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath );
-
-		}
-
-		return array;
-
-	},
-
-	needsTangents: function ( materials ) {
-
-		for( var i = 0, il = materials.length; i < il; i ++ ) {
-
-			var m = materials[ i ];
-
-			if ( m instanceof THREE.ShaderMaterial ) return true;
-
-		}
-
-		return false;
-
-	},
-
-	createMaterial: function ( m, texturePath ) {
-
-		var _this = this;
-
-		function is_pow2( n ) {
-
-			var l = Math.log( n ) / Math.LN2;
-			return Math.floor( l ) == l;
-
-		}
-
-		function nearest_pow2( n ) {
-
-			var l = Math.log( n ) / Math.LN2;
-			return Math.pow( 2, Math.round(  l ) );
-
-		}
-
-		function load_image( where, url ) {
-
-			var image = new Image();
-
-			image.onload = function () {
-
-				if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) {
-
-					var width = nearest_pow2( this.width );
-					var height = nearest_pow2( this.height );
-
-					where.image.width = width;
-					where.image.height = height;
-					where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height );
-
-				} else {
-
-					where.image = this;
-
-				}
-
-				where.needsUpdate = true;
-
-			};
-
-			image.crossOrigin = _this.crossOrigin;
-			image.src = url;
-
-		}
-
-		function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {
-
-			var isCompressed = /\.dds$/i.test( sourceFile );
-			var fullPath = texturePath + "/" + sourceFile;
-
-			if ( isCompressed ) {
-
-				var texture = THREE.ImageUtils.loadCompressedTexture( fullPath );
-
-				where[ name ] = texture;
-
-			} else {
-
-				var texture = document.createElement( 'canvas' );
-
-				where[ name ] = new THREE.Texture( texture );
-
-			}
-
-			where[ name ].sourceFile = sourceFile;
-
-			if( repeat ) {
-
-				where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] );
-
-				if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping;
-				if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping;
-
-			}
-
-			if ( offset ) {
-
-				where[ name ].offset.set( offset[ 0 ], offset[ 1 ] );
-
-			}
-
-			if ( wrap ) {
-
-				var wrapMap = {
-					"repeat": THREE.RepeatWrapping,
-					"mirror": THREE.MirroredRepeatWrapping
-				}
-
-				if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ];
-				if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ];
-
-			}
-
-			if ( anisotropy ) {
-
-				where[ name ].anisotropy = anisotropy;
-
-			}
-
-			if ( ! isCompressed ) {
-
-				load_image( where[ name ], fullPath );
-
-			}
-
-		}
-
-		function rgb2hex( rgb ) {
-
-			return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;
-
-		}
-
-		// defaults
-
-		var mtype = "MeshLambertMaterial";
-		var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };
-
-		// parameters from model file
-
-		if ( m.shading ) {
-
-			var shading = m.shading.toLowerCase();
-
-			if ( shading === "phong" ) mtype = "MeshPhongMaterial";
-			else if ( shading === "basic" ) mtype = "MeshBasicMaterial";
-
-		}
-
-		if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {
-
-			mpars.blending = THREE[ m.blending ];
-
-		}
-
-		if ( m.transparent !== undefined || m.opacity < 1.0 ) {
-
-			mpars.transparent = m.transparent;
-
-		}
-
-		if ( m.depthTest !== undefined ) {
-
-			mpars.depthTest = m.depthTest;
-
-		}
-
-		if ( m.depthWrite !== undefined ) {
-
-			mpars.depthWrite = m.depthWrite;
-
-		}
-
-		if ( m.visible !== undefined ) {
-
-			mpars.visible = m.visible;
-
-		}
-
-		if ( m.flipSided !== undefined ) {
-
-			mpars.side = THREE.BackSide;
-
-		}
-
-		if ( m.doubleSided !== undefined ) {
-
-			mpars.side = THREE.DoubleSide;
-
-		}
-
-		if ( m.wireframe !== undefined ) {
-
-			mpars.wireframe = m.wireframe;
-
-		}
-
-		if ( m.vertexColors !== undefined ) {
-
-			if ( m.vertexColors === "face" ) {
-
-				mpars.vertexColors = THREE.FaceColors;
-
-			} else if ( m.vertexColors ) {
-
-				mpars.vertexColors = THREE.VertexColors;
-
-			}
-
-		}
-
-		// colors
-
-		if ( m.colorDiffuse ) {
-
-			mpars.color = rgb2hex( m.colorDiffuse );
-
-		} else if ( m.DbgColor ) {
-
-			mpars.color = m.DbgColor;
-
-		}
-
-		if ( m.colorSpecular ) {
-
-			mpars.specular = rgb2hex( m.colorSpecular );
-
-		}
-
-		if ( m.colorAmbient ) {
-
-			mpars.ambient = rgb2hex( m.colorAmbient );
-
-		}
-
-		// modifiers
-
-		if ( m.transparency ) {
-
-			mpars.opacity = m.transparency;
-
-		}
-
-		if ( m.specularCoef ) {
-
-			mpars.shininess = m.specularCoef;
-
-		}
-
-		// textures
-
-		if ( m.mapDiffuse && texturePath ) {
-
-			create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
-
-		}
-
-		if ( m.mapLight && texturePath ) {
-
-			create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
-
-		}
-
-		if ( m.mapBump && texturePath ) {
-
-			create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
-
-		}
-
-		if ( m.mapNormal && texturePath ) {
-
-			create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
-
-		}
-
-		if ( m.mapSpecular && texturePath ) {
-
-			create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
-
-		}
-
-		//
-
-		if ( m.mapBumpScale ) {
-
-			mpars.bumpScale = m.mapBumpScale;
-
-		}
-
-		// special case for normal mapped material
-
-		if ( m.mapNormal ) {
-
-			var shader = THREE.ShaderLib[ "normalmap" ];
-			var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-			uniforms[ "tNormal" ].value = mpars.normalMap;
-
-			if ( m.mapNormalFactor ) {
-
-				uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor );
-
-			}
-
-			if ( mpars.map ) {
-
-				uniforms[ "tDiffuse" ].value = mpars.map;
-				uniforms[ "enableDiffuse" ].value = true;
-
-			}
-
-			if ( mpars.specularMap ) {
-
-				uniforms[ "tSpecular" ].value = mpars.specularMap;
-				uniforms[ "enableSpecular" ].value = true;
-
-			}
-
-			if ( mpars.lightMap ) {
-
-				uniforms[ "tAO" ].value = mpars.lightMap;
-				uniforms[ "enableAO" ].value = true;
-
-			}
-
-			// for the moment don't handle displacement texture
-
-			uniforms[ "uDiffuseColor" ].value.setHex( mpars.color );
-			uniforms[ "uSpecularColor" ].value.setHex( mpars.specular );
-			uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient );
-
-			uniforms[ "uShininess" ].value = mpars.shininess;
-
-			if ( mpars.opacity !== undefined ) {
-
-				uniforms[ "uOpacity" ].value = mpars.opacity;
-
-			}
-
-			var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
-			var material = new THREE.ShaderMaterial( parameters );
-
-			if ( mpars.transparent ) {
-
-				material.transparent = true;
-
-			}
-
-		} else {
-
-			var material = new THREE[ mtype ]( mpars );
-
-		}
-
-		if ( m.DbgName !== undefined ) material.name = m.DbgName;
-
-		return material;
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.ImageLoader = function () {
-
-	this.crossOrigin = null;
-
-};
-
-THREE.ImageLoader.prototype = {
-
-	constructor: THREE.ImageLoader,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	load: function ( url, image ) {
-
-		var scope = this;
-
-		if ( image === undefined ) image = new Image();
-
-		image.addEventListener( 'load', function () {
-
-			scope.dispatchEvent( { type: 'load', content: image } );
-
-		}, false );
-
-		image.addEventListener( 'error', function () {
-
-			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
-
-		}, false );
-
-		if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin;
-
-		image.src = url;
-
-	}
-
-}
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.JSONLoader = function ( showStatus ) {
-
-	THREE.Loader.call( this, showStatus );
-
-	this.withCredentials = false;
-
-};
-
-THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype );
-
-THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {
-
-	var scope = this;
-
-	// todo: unify load API to for easier SceneLoader use
-
-	texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url );
-
-	this.onLoadStart();
-	this.loadAjaxJSON( this, url, callback, texturePath );
-
-};
-
-THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) {
-
-	var xhr = new XMLHttpRequest();
-
-	var length = 0;
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === xhr.DONE ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				if ( xhr.responseText ) {
-
-					var json = JSON.parse( xhr.responseText );
-					var result = context.parse( json, texturePath );
-					callback( result.geometry, result.materials );
-
-				} else {
-
-					console.warn( "THREE.JSONLoader: [" + url + "] seems to be unreachable or file there is empty" );
-
-				}
-
-				// in context of more complex asset initialization
-				// do not block on single failed file
-				// maybe should go even one more level up
-
-				context.onLoadComplete();
-
-			} else {
-
-				console.error( "THREE.JSONLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );
-
-			}
-
-		} else if ( xhr.readyState === xhr.LOADING ) {
-
-			if ( callbackProgress ) {
-
-				if ( length === 0 ) {
-
-					length = xhr.getResponseHeader( "Content-Length" );
-
-				}
-
-				callbackProgress( { total: length, loaded: xhr.responseText.length } );
-
-			}
-
-		} else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) {
-
-			if ( callbackProgress !== undefined ) {
-
-				length = xhr.getResponseHeader( "Content-Length" );
-
-			}
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.withCredentials = this.withCredentials;
-	xhr.send( null );
-
-};
-
-THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
-
-	var scope = this,
-	geometry = new THREE.Geometry(),
-	scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
-
-	parseModel( scale );
-
-	parseSkin();
-	parseMorphing( scale );
-
-	geometry.computeCentroids();
-	geometry.computeFaceNormals();
-
-	function parseModel( scale ) {
-
-		function isBitSet( value, position ) {
-
-			return value & ( 1 << position );
-
-		}
-
-		var i, j, fi,
-
-		offset, zLength, nVertices,
-
-		colorIndex, normalIndex, uvIndex, materialIndex,
-
-		type,
-		isQuad,
-		hasMaterial,
-		hasFaceUv, hasFaceVertexUv,
-		hasFaceNormal, hasFaceVertexNormal,
-		hasFaceColor, hasFaceVertexColor,
-
-		vertex, face, color, normal,
-
-		uvLayer, uvs, u, v,
-
-		faces = json.faces,
-		vertices = json.vertices,
-		normals = json.normals,
-		colors = json.colors,
-
-		nUvLayers = 0;
-
-		// disregard empty arrays
-
-		for ( i = 0; i < json.uvs.length; i++ ) {
-
-			if ( json.uvs[ i ].length ) nUvLayers ++;
-
-		}
-
-		for ( i = 0; i < nUvLayers; i++ ) {
-
-			geometry.faceUvs[ i ] = [];
-			geometry.faceVertexUvs[ i ] = [];
-
-		}
-
-		offset = 0;
-		zLength = vertices.length;
-
-		while ( offset < zLength ) {
-
-			vertex = new THREE.Vector3();
-
-			vertex.x = vertices[ offset ++ ] * scale;
-			vertex.y = vertices[ offset ++ ] * scale;
-			vertex.z = vertices[ offset ++ ] * scale;
-
-			geometry.vertices.push( vertex );
-
-		}
-
-		offset = 0;
-		zLength = faces.length;
-
-		while ( offset < zLength ) {
-
-			type = faces[ offset ++ ];
-
-
-			isQuad              = isBitSet( type, 0 );
-			hasMaterial         = isBitSet( type, 1 );
-			hasFaceUv           = isBitSet( type, 2 );
-			hasFaceVertexUv     = isBitSet( type, 3 );
-			hasFaceNormal       = isBitSet( type, 4 );
-			hasFaceVertexNormal = isBitSet( type, 5 );
-			hasFaceColor	    = isBitSet( type, 6 );
-			hasFaceVertexColor  = isBitSet( type, 7 );
-
-			//console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
-
-			if ( isQuad ) {
-
-				face = new THREE.Face4();
-
-				face.a = faces[ offset ++ ];
-				face.b = faces[ offset ++ ];
-				face.c = faces[ offset ++ ];
-				face.d = faces[ offset ++ ];
-
-				nVertices = 4;
-
-			} else {
-
-				face = new THREE.Face3();
-
-				face.a = faces[ offset ++ ];
-				face.b = faces[ offset ++ ];
-				face.c = faces[ offset ++ ];
-
-				nVertices = 3;
-
-			}
-
-			if ( hasMaterial ) {
-
-				materialIndex = faces[ offset ++ ];
-				face.materialIndex = materialIndex;
-
-			}
-
-			// to get face <=> uv index correspondence
-
-			fi = geometry.faces.length;
-
-			if ( hasFaceUv ) {
-
-				for ( i = 0; i < nUvLayers; i++ ) {
-
-					uvLayer = json.uvs[ i ];
-
-					uvIndex = faces[ offset ++ ];
-
-					u = uvLayer[ uvIndex * 2 ];
-					v = uvLayer[ uvIndex * 2 + 1 ];
-
-					geometry.faceUvs[ i ][ fi ] = new THREE.Vector2( u, v );
-
-				}
-
-			}
-
-			if ( hasFaceVertexUv ) {
-
-				for ( i = 0; i < nUvLayers; i++ ) {
-
-					uvLayer = json.uvs[ i ];
-
-					uvs = [];
-
-					for ( j = 0; j < nVertices; j ++ ) {
-
-						uvIndex = faces[ offset ++ ];
-
-						u = uvLayer[ uvIndex * 2 ];
-						v = uvLayer[ uvIndex * 2 + 1 ];
-
-						uvs[ j ] = new THREE.Vector2( u, v );
-
-					}
-
-					geometry.faceVertexUvs[ i ][ fi ] = uvs;
-
-				}
-
-			}
-
-			if ( hasFaceNormal ) {
-
-				normalIndex = faces[ offset ++ ] * 3;
-
-				normal = new THREE.Vector3();
-
-				normal.x = normals[ normalIndex ++ ];
-				normal.y = normals[ normalIndex ++ ];
-				normal.z = normals[ normalIndex ];
-
-				face.normal = normal;
-
-			}
-
-			if ( hasFaceVertexNormal ) {
-
-				for ( i = 0; i < nVertices; i++ ) {
-
-					normalIndex = faces[ offset ++ ] * 3;
-
-					normal = new THREE.Vector3();
-
-					normal.x = normals[ normalIndex ++ ];
-					normal.y = normals[ normalIndex ++ ];
-					normal.z = normals[ normalIndex ];
-
-					face.vertexNormals.push( normal );
-
-				}
-
-			}
-
-
-			if ( hasFaceColor ) {
-
-				colorIndex = faces[ offset ++ ];
-
-				color = new THREE.Color( colors[ colorIndex ] );
-				face.color = color;
-
-			}
-
-
-			if ( hasFaceVertexColor ) {
-
-				for ( i = 0; i < nVertices; i++ ) {
-
-					colorIndex = faces[ offset ++ ];
-
-					color = new THREE.Color( colors[ colorIndex ] );
-					face.vertexColors.push( color );
-
-				}
-
-			}
-
-			geometry.faces.push( face );
-
-		}
-
-	};
-
-	function parseSkin() {
-
-		var i, l, x, y, z, w, a, b, c, d;
-
-		if ( json.skinWeights ) {
-
-			for ( i = 0, l = json.skinWeights.length; i < l; i += 2 ) {
-
-				x = json.skinWeights[ i     ];
-				y = json.skinWeights[ i + 1 ];
-				z = 0;
-				w = 0;
-
-				geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );
-
-			}
-
-		}
-
-		if ( json.skinIndices ) {
-
-			for ( i = 0, l = json.skinIndices.length; i < l; i += 2 ) {
-
-				a = json.skinIndices[ i     ];
-				b = json.skinIndices[ i + 1 ];
-				c = 0;
-				d = 0;
-
-				geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );
-
-			}
-
-		}
-
-		geometry.bones = json.bones;
-		geometry.animation = json.animation;
-
-	};
-
-	function parseMorphing( scale ) {
-
-		if ( json.morphTargets !== undefined ) {
-
-			var i, l, v, vl, dstVertices, srcVertices;
-
-			for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {
-
-				geometry.morphTargets[ i ] = {};
-				geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
-				geometry.morphTargets[ i ].vertices = [];
-
-				dstVertices = geometry.morphTargets[ i ].vertices;
-				srcVertices = json.morphTargets [ i ].vertices;
-
-				for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
-
-					var vertex = new THREE.Vector3();
-					vertex.x = srcVertices[ v ] * scale;
-					vertex.y = srcVertices[ v + 1 ] * scale;
-					vertex.z = srcVertices[ v + 2 ] * scale;
-
-					dstVertices.push( vertex );
-
-				}
-
-			}
-
-		}
-
-		if ( json.morphColors !== undefined ) {
-
-			var i, l, c, cl, dstColors, srcColors, color;
-
-			for ( i = 0, l = json.morphColors.length; i < l; i++ ) {
-
-				geometry.morphColors[ i ] = {};
-				geometry.morphColors[ i ].name = json.morphColors[ i ].name;
-				geometry.morphColors[ i ].colors = [];
-
-				dstColors = geometry.morphColors[ i ].colors;
-				srcColors = json.morphColors [ i ].colors;
-
-				for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) {
-
-					color = new THREE.Color( 0xffaa00 );
-					color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );
-					dstColors.push( color );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	if ( json.materials === undefined ) {
-
-		return { geometry: geometry };
-
-	} else {
-
-		var materials = this.initMaterials( json.materials, texturePath );
-
-		if ( this.needsTangents( materials ) ) {
-
-			geometry.computeTangents();
-
-		}
-
-		return { geometry: geometry, materials: materials };
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.LoadingMonitor = function () {
-
-	var scope = this;
-
-	var loaded = 0;
-	var total = 0;
-
-	var onLoad = function ( event ) {
-
-		loaded ++;
-
-		scope.dispatchEvent( { type: 'progress', loaded: loaded, total: total } );
-
-		if ( loaded === total ) {
-
-			scope.dispatchEvent( { type: 'load' } );
-
-		}
-
-	};
-
-	this.add = function ( loader ) {
-
-		total ++;
-
-		loader.addEventListener( 'load', onLoad, false );
-
-	};
-
-};
-
-THREE.LoadingMonitor.prototype = {
-
-	constructor: THREE.LoadingMonitor,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.GeometryLoader = function () {};
-THREE.GeometryLoader.prototype = {
-
-	constructor: THREE.GeometryLoader,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	load: function ( url ) {
-
-		var scope = this;
-		var request = new XMLHttpRequest();
-
-		request.addEventListener( 'load', function ( event ) {
-
-			var response = scope.parse( JSON.parse( event.target.responseText ) );
-
-			scope.dispatchEvent( { type: 'load', content: response } );
-
-		}, false );
-
-		request.addEventListener( 'progress', function ( event ) {
-
-			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
-
-		}, false );
-
-		request.addEventListener( 'error', function () {
-
-			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
-
-		}, false );
-
-		request.open( 'GET', url, true );
-		request.send( null );
-
-	},
-
-	parse: function ( json ) {
-
-		
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.MaterialLoader = function () {};
-
-THREE.MaterialLoader.prototype = {
-
-	constructor: THREE.MaterialLoader,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	load: function ( url ) {
-
-		var scope = this;
-		var request = new XMLHttpRequest();
-
-		request.addEventListener( 'load', function ( event ) {
-
-			var response = scope.parse( JSON.parse( event.target.responseText ) );
-
-			scope.dispatchEvent( { type: 'load', content: response } );
-
-		}, false );
-
-		request.addEventListener( 'progress', function ( event ) {
-
-			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
-
-		}, false );
-
-		request.addEventListener( 'error', function () {
-
-			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
-
-		}, false );
-
-		request.open( 'GET', url, true );
-		request.send( null );
-
-	},
-
-	parse: function ( json ) {
-
-		var material;
-
-		switch ( json.type ) {
-
-			case 'MeshBasicMaterial':
-
-				material = new THREE.MeshBasicMaterial( {
-
-					color: json.color,
-					opacity: json.opacity,
-					transparent: json.transparent,
-					wireframe: json.wireframe
-
-				} );
-
-				break;
-
-			case 'MeshLambertMaterial':
-
-				material = new THREE.MeshLambertMaterial( {
-
-					color: json.color,
-					ambient: json.ambient,
-					emissive: json.emissive,
-					opacity: json.opacity,
-					transparent: json.transparent,
-					wireframe: json.wireframe
-
-				} );
-
-				break;
-
-			case 'MeshPhongMaterial':
-
-				material = new THREE.MeshPhongMaterial( {
-
-					color: json.color,
-					ambient: json.ambient,
-					emissive: json.emissive,
-					specular: json.specular,
-					shininess: json.shininess,
-					opacity: json.opacity,
-					transparent: json.transparent,
-					wireframe: json.wireframe
-
-				} );
-
-				break;
-
-			case 'MeshNormalMaterial':
-
-				material = new THREE.MeshNormalMaterial( {
-
-					opacity: json.opacity,
-					transparent: json.transparent,
-					wireframe: json.wireframe
-
-				} );
-
-				break;
-
-			case 'MeshDepthMaterial':
-
-				material = new THREE.MeshDepthMaterial( {
-
-					opacity: json.opacity,
-					transparent: json.transparent,
-					wireframe: json.wireframe
-
-				} );
-
-				break;
-
-		}
-
-		return material;
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SceneLoader = function () {
-
-	this.onLoadStart = function () {};
-	this.onLoadProgress = function() {};
-	this.onLoadComplete = function () {};
-
-	this.callbackSync = function () {};
-	this.callbackProgress = function () {};
-
-	this.geometryHandlerMap = {};
-	this.hierarchyHandlerMap = {};
-
-	this.addGeometryHandler( "ascii", THREE.JSONLoader );
-
-};
-
-THREE.SceneLoader.prototype.constructor = THREE.SceneLoader;
-
-THREE.SceneLoader.prototype.load = function ( url, callbackFinished ) {
-
-	var scope = this;
-
-	var xhr = new XMLHttpRequest();
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === 4 ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				var json = JSON.parse( xhr.responseText );
-				scope.parse( json, callbackFinished, url );
-
-			} else {
-
-				console.error( "THREE.SceneLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );
-
-			}
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.send( null );
-
-};
-
-THREE.SceneLoader.prototype.addGeometryHandler = function ( typeID, loaderClass ) {
-
-	this.geometryHandlerMap[ typeID ] = { "loaderClass": loaderClass };
-
-};
-
-THREE.SceneLoader.prototype.addHierarchyHandler = function ( typeID, loaderClass ) {
-
-	this.hierarchyHandlerMap[ typeID ] = { "loaderClass": loaderClass };
-
-};
-
-THREE.SceneLoader.prototype.parse = function ( json, callbackFinished, url ) {
-
-	var scope = this;
-
-	var urlBase = THREE.Loader.prototype.extractUrlBase( url );
-
-	var geometry, material, camera, fog,
-		texture, images, color,
-		light, hex, intensity,
-		counter_models, counter_textures,
-		total_models, total_textures,
-		result;
-
-	var target_array = [];
-
-	var data = json;
-
-	// async geometry loaders
-
-	for ( var typeID in this.geometryHandlerMap ) {
-
-		var loaderClass = this.geometryHandlerMap[ typeID ][ "loaderClass" ];
-		this.geometryHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass();
-
-	}
-
-	// async hierachy loaders
-
-	for ( var typeID in this.hierarchyHandlerMap ) {
-
-		var loaderClass = this.hierarchyHandlerMap[ typeID ][ "loaderClass" ];
-		this.hierarchyHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass();
-
-	}
-
-	counter_models = 0;
-	counter_textures = 0;
-
-	result = {
-
-		scene: new THREE.Scene(),
-		geometries: {},
-		face_materials: {},
-		materials: {},
-		textures: {},
-		objects: {},
-		cameras: {},
-		lights: {},
-		fogs: {},
-		empties: {},
-		groups: {}
-
-	};
-
-	if ( data.transform ) {
-
-		var position = data.transform.position,
-			rotation = data.transform.rotation,
-			scale = data.transform.scale;
-
-		if ( position )
-			result.scene.position.set( position[ 0 ], position[ 1 ], position [ 2 ] );
-
-		if ( rotation )
-			result.scene.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation [ 2 ] );
-
-		if ( scale )
-			result.scene.scale.set( scale[ 0 ], scale[ 1 ], scale [ 2 ] );
-
-		if ( position || rotation || scale ) {
-
-			result.scene.updateMatrix();
-			result.scene.updateMatrixWorld();
-
-		}
-
-	}
-
-	function get_url( source_url, url_type ) {
-
-		if ( url_type == "relativeToHTML" ) {
-
-			return source_url;
-
-		} else {
-
-			return urlBase + "/" + source_url;
-
-		}
-
-	};
-
-	// toplevel loader function, delegates to handle_children
-
-	function handle_objects() {
-
-		handle_children( result.scene, data.objects );
-
-	}
-
-	// handle all the children from the loaded json and attach them to given parent
-
-	function handle_children( parent, children ) {
-
-		var mat, dst, pos, rot, scl, quat;
-
-		for ( var objID in children ) {
-
-			// check by id if child has already been handled,
-			// if not, create new object
-
-			if ( result.objects[ objID ] === undefined ) {
-
-				var objJSON = children[ objID ];
-
-				var object = null;
-
-				// meshes
-
-				if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlerMap ) ) {
-
-					if ( objJSON.loading === undefined ) {
-
-						var reservedTypes = { "type": 1, "url": 1, "material": 1,
-											  "position": 1, "rotation": 1, "scale" : 1,
-											  "visible": 1, "children": 1, "userData": 1,
-											  "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 };
-
-						var loaderParameters = {};
-
-						for ( var parType in objJSON ) {
-
-							if ( ! ( parType in reservedTypes ) ) {
-
-								loaderParameters[ parType ] = objJSON[ parType ];
-
-							}
-
-						}
-
-						material = result.materials[ objJSON.material ];
-
-						objJSON.loading = true;
-
-						var loader = scope.hierarchyHandlerMap[ objJSON.type ][ "loaderObject" ];
-
-						// ColladaLoader
-
-						if ( loader.options ) {
-
-							loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) );
-
-						// UTF8Loader
-						// OBJLoader
-
-						} else {
-
-							loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters );
-
-						}
-
-					}
-
-				} else if ( objJSON.geometry !== undefined ) {
-
-					geometry = result.geometries[ objJSON.geometry ];
-
-					// geometry already loaded
-
-					if ( geometry ) {
-
-						var needsTangents = false;
-
-						material = result.materials[ objJSON.material ];
-						needsTangents = material instanceof THREE.ShaderMaterial;
-
-						pos = objJSON.position;
-						rot = objJSON.rotation;
-						scl = objJSON.scale;
-						mat = objJSON.matrix;
-						quat = objJSON.quaternion;
-
-						// use materials from the model file
-						// if there is no material specified in the object
-
-						if ( ! objJSON.material ) {
-
-							material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] );
-
-						}
-
-						// use materials from the model file
-						// if there is just empty face material
-						// (must create new material as each model has its own face material)
-
-						if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) {
-
-							material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] );
-
-						}
-
-						if ( material instanceof THREE.MeshFaceMaterial ) {
-
-							for ( var i = 0; i < material.materials.length; i ++ ) {
-
-								needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial );
-
-							}
-
-						}
-
-						if ( needsTangents ) {
-
-							geometry.computeTangents();
-
-						}
-
-						if ( objJSON.skin ) {
-
-							object = new THREE.SkinnedMesh( geometry, material );
-
-						} else if ( objJSON.morph ) {
-
-							object = new THREE.MorphAnimMesh( geometry, material );
-
-							if ( objJSON.duration !== undefined ) {
-
-								object.duration = objJSON.duration;
-
-							}
-
-							if ( objJSON.time !== undefined ) {
-
-								object.time = objJSON.time;
-
-							}
-
-							if ( objJSON.mirroredLoop !== undefined ) {
-
-								object.mirroredLoop = objJSON.mirroredLoop;
-
-							}
-
-							if ( material.morphNormals ) {
-
-								geometry.computeMorphNormals();
-
-							}
-
-						} else {
-
-							object = new THREE.Mesh( geometry, material );
-
-						}
-
-						object.name = objID;
-
-						if ( mat ) {
-
-							object.matrixAutoUpdate = false;
-							object.matrix.set(
-								mat[0],  mat[1],  mat[2],  mat[3],
-								mat[4],  mat[5],  mat[6],  mat[7],
-								mat[8],  mat[9],  mat[10], mat[11],
-								mat[12], mat[13], mat[14], mat[15]
-							);
-
-						} else {
-
-							object.position.set( pos[0], pos[1], pos[2] );
-
-							if ( quat ) {
-
-								object.quaternion.set( quat[0], quat[1], quat[2], quat[3] );
-								object.useQuaternion = true;
-
-							} else {
-
-								object.rotation.set( rot[0], rot[1], rot[2] );
-
-							}
-
-							object.scale.set( scl[0], scl[1], scl[2] );
-
-						}
-
-						object.visible = objJSON.visible;
-						object.castShadow = objJSON.castShadow;
-						object.receiveShadow = objJSON.receiveShadow;
-
-						parent.add( object );
-
-						result.objects[ objID ] = object;
-
-					}
-
-				// lights
-
-				} else if ( objJSON.type === "DirectionalLight" || objJSON.type === "PointLight" || objJSON.type === "AmbientLight" ) {
-
-					hex = ( objJSON.color !== undefined ) ? objJSON.color : 0xffffff;
-					intensity = ( objJSON.intensity !== undefined ) ? objJSON.intensity : 1;
-
-					if ( objJSON.type === "DirectionalLight" ) {
-
-						pos = objJSON.direction;
-
-						light = new THREE.DirectionalLight( hex, intensity );
-						light.position.set( pos[0], pos[1], pos[2] );
-
-						if ( objJSON.target ) {
-
-							target_array.push( { "object": light, "targetName" : objJSON.target } );
-
-							// kill existing default target
-							// otherwise it gets added to scene when parent gets added
-
-							light.target = null;
-
-						}
-
-					} else if ( objJSON.type === "PointLight" ) {
-
-						pos = objJSON.position;
-						dst = objJSON.distance;
-
-						light = new THREE.PointLight( hex, intensity, dst );
-						light.position.set( pos[0], pos[1], pos[2] );
-
-					} else if ( objJSON.type === "AmbientLight" ) {
-
-						light = new THREE.AmbientLight( hex );
-
-					}
-
-					parent.add( light );
-
-					light.name = objID;
-					result.lights[ objID ] = light;
-					result.objects[ objID ] = light;
-
-				// cameras
-
-				} else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) {
-
-					pos = objJSON.position;
-					rot = objJSON.rotation;
-					quat = objJSON.quaternion;
-
-					if ( objJSON.type === "PerspectiveCamera" ) {
-
-						camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far );
-
-					} else if ( objJSON.type === "OrthographicCamera" ) {
-
-						camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far );
-
-					}
-
-					camera.name = objID;
-					camera.position.set( pos[0], pos[1], pos[2] );
-
-					if ( quat !== undefined ) {
-
-						camera.quaternion.set( quat[0], quat[1], quat[2], quat[3] );
-						camera.useQuaternion = true;
-
-					} else if ( rot !== undefined ) {
-
-						camera.rotation.set( rot[0], rot[1], rot[2] );
-
-					}
-
-					parent.add( camera );
-
-					result.cameras[ objID ] = camera;
-					result.objects[ objID ] = camera;
-
-				// pure Object3D
-
-				} else {
-
-					pos = objJSON.position;
-					rot = objJSON.rotation;
-					scl = objJSON.scale;
-					quat = objJSON.quaternion;
-
-					object = new THREE.Object3D();
-					object.name = objID;
-					object.position.set( pos[0], pos[1], pos[2] );
-
-					if ( quat ) {
-
-						object.quaternion.set( quat[0], quat[1], quat[2], quat[3] );
-						object.useQuaternion = true;
-
-					} else {
-
-						object.rotation.set( rot[0], rot[1], rot[2] );
-
-					}
-
-					object.scale.set( scl[0], scl[1], scl[2] );
-					object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false;
-
-					parent.add( object );
-
-					result.objects[ objID ] = object;
-					result.empties[ objID ] = object;
-
-				}
-
-				if ( object ) {
-
-					if ( objJSON.userData !== undefined )  {
-
-						for ( var key in objJSON.userData ) {
-
-							var value = objJSON.userData[ key ];
-							object.userData[ key ] = value;
-
-						}
-
-					}
-
-					if ( objJSON.groups !== undefined ) {
-
-						for ( var i = 0; i < objJSON.groups.length; i ++ ) {
-
-							var groupID = objJSON.groups[ i ];
-
-							if ( result.groups[ groupID ] === undefined ) {
-
-								result.groups[ groupID ] = [];
-
-							}
-
-							result.groups[ groupID ].push( objID );
-
-						}
-
-					}
-
-					if ( objJSON.children !== undefined ) {
-
-						handle_children( object, objJSON.children );
-
-					}
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function handle_mesh( geo, mat, id ) {
-
-		result.geometries[ id ] = geo;
-		result.face_materials[ id ] = mat;
-		handle_objects();
-
-	};
-
-	function handle_hierarchy( node, id, parent, material, obj ) {
-
-		var p = obj.position;
-		var r = obj.rotation;
-		var q = obj.quaternion;
-		var s = obj.scale;
-
-		node.position.set( p[0], p[1], p[2] );
-
-		if ( q ) {
-
-			node.quaternion.set( q[0], q[1], q[2], q[3] );
-			node.useQuaternion = true;
-
-		} else {
-
-			node.rotation.set( r[0], r[1], r[2] );
-
-		}
-
-		node.scale.set( s[0], s[1], s[2] );
-
-		// override children materials
-		// if object material was specified in JSON explicitly
-
-		if ( material ) {
-
-			node.traverse( function ( child )  {
-
-				child.material = material;
-
-			} );
-
-		}
-
-		// override children visibility
-		// with root node visibility as specified in JSON
-
-		var visible = ( obj.visible !== undefined ) ? obj.visible : true;
-
-		node.traverse( function ( child )  {
-
-			child.visible = visible;
-
-		} );
-
-		parent.add( node );
-
-		node.name = id;
-
-		result.objects[ id ] = node;
-		handle_objects();
-
-	};
-
-	function create_callback_geometry( id ) {
-
-		return function ( geo, mat ) {
-
-			geo.name = id;
-
-			handle_mesh( geo, mat, id );
-
-			counter_models -= 1;
-
-			scope.onLoadComplete();
-
-			async_callback_gate();
-
-		}
-
-	};
-
-	function create_callback_hierachy( id, parent, material, obj ) {
-
-		return function ( event ) {
-
-			var result;
-
-			// loaders which use EventDispatcher
-
-			if ( event.content ) {
-
-				result = event.content;
-
-			// ColladaLoader
-
-			} else if ( event.dae ) {
-
-				result = event.scene;
-
-
-			// UTF8Loader
-
-			} else {
-
-				result = event;
-
-			}
-
-			handle_hierarchy( result, id, parent, material, obj );
-
-			counter_models -= 1;
-
-			scope.onLoadComplete();
-
-			async_callback_gate();
-
-		}
-
-	};
-
-	function create_callback_embed( id ) {
-
-		return function ( geo, mat ) {
-
-			geo.name = id;
-
-			result.geometries[ id ] = geo;
-			result.face_materials[ id ] = mat;
-
-		}
-
-	};
-
-	function async_callback_gate() {
-
-		var progress = {
-
-			totalModels : total_models,
-			totalTextures : total_textures,
-			loadedModels : total_models - counter_models,
-			loadedTextures : total_textures - counter_textures
-
-		};
-
-		scope.callbackProgress( progress, result );
-
-		scope.onLoadProgress();
-
-		if ( counter_models === 0 && counter_textures === 0 ) {
-
-			finalize();
-			callbackFinished( result );
-
-		}
-
-	};
-
-	function finalize() {
-
-		// take care of targets which could be asynchronously loaded objects
-
-		for ( var i = 0; i < target_array.length; i ++ ) {
-
-			var ta = target_array[ i ];
-
-			var target = result.objects[ ta.targetName ];
-
-			if ( target ) {
-
-				ta.object.target = target;
-
-			} else {
-
-				// if there was error and target of specified name doesn't exist in the scene file
-				// create instead dummy target
-				// (target must be added to scene explicitly as parent is already added)
-
-				ta.object.target = new THREE.Object3D();
-				result.scene.add( ta.object.target );
-
-			}
-
-			ta.object.target.userData.targetInverse = ta.object;
-
-		}
-
-	};
-
-	var callbackTexture = function ( count ) {
-
-		counter_textures -= count;
-		async_callback_gate();
-
-		scope.onLoadComplete();
-
-	};
-
-	// must use this instead of just directly calling callbackTexture
-	// because of closure in the calling context loop
-
-	var generateTextureCallback = function ( count ) {
-
-		return function () {
-
-			callbackTexture( count );
-
-		};
-
-	};
-
-	// first go synchronous elements
-
-	// fogs
-
-	var fogID, fogJSON;
-
-	for ( fogID in data.fogs ) {
-
-		fogJSON = data.fogs[ fogID ];
-
-		if ( fogJSON.type === "linear" ) {
-
-			fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far );
-
-		} else if ( fogJSON.type === "exp2" ) {
-
-			fog = new THREE.FogExp2( 0x000000, fogJSON.density );
-
-		}
-
-		color = fogJSON.color;
-		fog.color.setRGB( color[0], color[1], color[2] );
-
-		result.fogs[ fogID ] = fog;
-
-	}
-
-	// now come potentially asynchronous elements
-
-	// geometries
-
-	// count how many geometries will be loaded asynchronously
-
-	var geoID, geoJSON;
-
-	for ( geoID in data.geometries ) {
-
-		geoJSON = data.geometries[ geoID ];
-
-		if ( geoJSON.type in this.geometryHandlerMap ) {
-
-			counter_models += 1;
-
-			scope.onLoadStart();
-
-		}
-
-	}
-
-	// count how many hierarchies will be loaded asynchronously
-
-	var objID, objJSON;
-
-	for ( objID in data.objects ) {
-
-		objJSON = data.objects[ objID ];
-
-		if ( objJSON.type && ( objJSON.type in this.hierarchyHandlerMap ) ) {
-
-			counter_models += 1;
-
-			scope.onLoadStart();
-
-		}
-
-	}
-
-	total_models = counter_models;
-
-	for ( geoID in data.geometries ) {
-
-		geoJSON = data.geometries[ geoID ];
-
-		if ( geoJSON.type === "cube" ) {
-
-			geometry = new THREE.CubeGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type === "plane" ) {
-
-			geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type === "sphere" ) {
-
-			geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type === "cylinder" ) {
-
-			geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type === "torus" ) {
-
-			geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type === "icosahedron" ) {
-
-			geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions );
-			geometry.name = geoID;
-			result.geometries[ geoID ] = geometry;
-
-		} else if ( geoJSON.type in this.geometryHandlerMap ) {
-
-			var loaderParameters = {};
-
-			for ( var parType in geoJSON ) {
-
-				if ( parType !== "type" && parType !== "url" ) {
-
-					loaderParameters[ parType ] = geoJSON[ parType ];
-
-				}
-
-			}
-
-			var loader = this.geometryHandlerMap[ geoJSON.type ][ "loaderObject" ];
-			loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters );
-
-		} else if ( geoJSON.type === "embedded" ) {
-
-			var modelJson = data.embeds[ geoJSON.id ],
-				texture_path = "";
-
-			// pass metadata along to jsonLoader so it knows the format version
-
-			modelJson.metadata = data.metadata;
-
-			if ( modelJson ) {
-
-				var jsonLoader = this.geometryHandlerMap[ "ascii" ][ "loaderObject" ];
-				var model = jsonLoader.parse( modelJson, texture_path );
-				create_callback_embed( geoID )( model.geometry, model.materials );
-
-			}
-
-		}
-
-	}
-
-	// textures
-
-	// count how many textures will be loaded asynchronously
-
-	var textureID, textureJSON;
-
-	for ( textureID in data.textures ) {
-
-		textureJSON = data.textures[ textureID ];
-
-		if ( textureJSON.url instanceof Array ) {
-
-			counter_textures += textureJSON.url.length;
-
-			for( var n = 0; n < textureJSON.url.length; n ++ ) {
-
-				scope.onLoadStart();
-
-			}
-
-		} else {
-
-			counter_textures += 1;
-
-			scope.onLoadStart();
-
-		}
-
-	}
-
-	total_textures = counter_textures;
-
-	for ( textureID in data.textures ) {
-
-		textureJSON = data.textures[ textureID ];
-
-		if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined  ) {
-
-			textureJSON.mapping = new THREE[ textureJSON.mapping ]();
-
-		}
-
-		if ( textureJSON.url instanceof Array ) {
-
-			var count = textureJSON.url.length;
-			var url_array = [];
-
-			for( var i = 0; i < count; i ++ ) {
-
-				url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType );
-
-			}
-
-			var isCompressed = /\.dds$/i.test( url_array[ 0 ] );
-
-			if ( isCompressed ) {
-
-				texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) );
-
-			} else {
-
-				texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) );
-
-			}
-
-		} else {
-
-			var isCompressed = /\.dds$/i.test( textureJSON.url );
-			var fullUrl = get_url( textureJSON.url, data.urlBaseType );
-			var textureCallback = generateTextureCallback( 1 );
-
-			if ( isCompressed ) {
-
-				texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback );
-
-			} else {
-
-				texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback );
-
-			}
-
-			if ( THREE[ textureJSON.minFilter ] !== undefined )
-				texture.minFilter = THREE[ textureJSON.minFilter ];
-
-			if ( THREE[ textureJSON.magFilter ] !== undefined )
-				texture.magFilter = THREE[ textureJSON.magFilter ];
-
-			if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy;
-
-			if ( textureJSON.repeat ) {
-
-				texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] );
-
-				if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
-				if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
-
-			}
-
-			if ( textureJSON.offset ) {
-
-				texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] );
-
-			}
-
-			// handle wrap after repeat so that default repeat can be overriden
-
-			if ( textureJSON.wrap ) {
-
-				var wrapMap = {
-				"repeat" 	: THREE.RepeatWrapping,
-				"mirror"	: THREE.MirroredRepeatWrapping
-				}
-
-				if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ];
-				if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ];
-
-			}
-
-		}
-
-		result.textures[ textureID ] = texture;
-
-	}
-
-	// materials
-
-	var matID, matJSON;
-	var parID;
-
-	for ( matID in data.materials ) {
-
-		matJSON = data.materials[ matID ];
-
-		for ( parID in matJSON.parameters ) {
-
-			if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) {
-
-				matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ];
-
-			} else if ( parID === "shading" ) {
-
-				matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading;
-
-			} else if ( parID === "side" ) {
-
-				if ( matJSON.parameters[ parID ] == "double" ) {
-
-					matJSON.parameters[ parID ] = THREE.DoubleSide;
-
-				} else if ( matJSON.parameters[ parID ] == "back" ) {
-
-					matJSON.parameters[ parID ] = THREE.BackSide;
-
-				} else {
-
-					matJSON.parameters[ parID ] = THREE.FrontSide;
-
-				}
-
-			} else if ( parID === "blending" ) {
-
-				matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending;
-
-			} else if ( parID === "combine" ) {
-
-				matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation;
-
-			} else if ( parID === "vertexColors" ) {
-
-				if ( matJSON.parameters[ parID ] == "face" ) {
-
-					matJSON.parameters[ parID ] = THREE.FaceColors;
-
-				// default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false
-
-				} else if ( matJSON.parameters[ parID ] )   {
-
-					matJSON.parameters[ parID ] = THREE.VertexColors;
-
-				}
-
-			} else if ( parID === "wrapRGB" ) {
-
-				var v3 = matJSON.parameters[ parID ];
-				matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] );
-
-			}
-
-		}
-
-		if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) {
-
-			matJSON.parameters.transparent = true;
-
-		}
-
-		if ( matJSON.parameters.normalMap ) {
-
-			var shader = THREE.ShaderLib[ "normalmap" ];
-			var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-			var diffuse = matJSON.parameters.color;
-			var specular = matJSON.parameters.specular;
-			var ambient = matJSON.parameters.ambient;
-			var shininess = matJSON.parameters.shininess;
-
-			uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ];
-
-			if ( matJSON.parameters.normalScale ) {
-
-				uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] );
-
-			}
-
-			if ( matJSON.parameters.map ) {
-
-				uniforms[ "tDiffuse" ].value = matJSON.parameters.map;
-				uniforms[ "enableDiffuse" ].value = true;
-
-			}
-
-			if ( matJSON.parameters.envMap ) {
-
-				uniforms[ "tCube" ].value = matJSON.parameters.envMap;
-				uniforms[ "enableReflection" ].value = true;
-				uniforms[ "uReflectivity" ].value = matJSON.parameters.reflectivity;
-
-			}
-
-			if ( matJSON.parameters.lightMap ) {
-
-				uniforms[ "tAO" ].value = matJSON.parameters.lightMap;
-				uniforms[ "enableAO" ].value = true;
-
-			}
-
-			if ( matJSON.parameters.specularMap ) {
-
-				uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ];
-				uniforms[ "enableSpecular" ].value = true;
-
-			}
-
-			if ( matJSON.parameters.displacementMap ) {
-
-				uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ];
-				uniforms[ "enableDisplacement" ].value = true;
-
-				uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias;
-				uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale;
-
-			}
-
-			uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
-			uniforms[ "uSpecularColor" ].value.setHex( specular );
-			uniforms[ "uAmbientColor" ].value.setHex( ambient );
-
-			uniforms[ "uShininess" ].value = shininess;
-
-			if ( matJSON.parameters.opacity ) {
-
-				uniforms[ "uOpacity" ].value = matJSON.parameters.opacity;
-
-			}
-
-			var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
-
-			material = new THREE.ShaderMaterial( parameters );
-
-		} else {
-
-			material = new THREE[ matJSON.type ]( matJSON.parameters );
-
-		}
-
-		material.name = matID;
-
-		result.materials[ matID ] = material;
-
-	}
-
-	// second pass through all materials to initialize MeshFaceMaterials
-	// that could be referring to other materials out of order
-
-	for ( matID in data.materials ) {
-
-		matJSON = data.materials[ matID ];
-
-		if ( matJSON.parameters.materials ) {
-
-			var materialArray = [];
-
-			for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) {
-
-				var label = matJSON.parameters.materials[ i ];
-				materialArray.push( result.materials[ label ] );
-
-			}
-
-			result.materials[ matID ].materials = materialArray;
-
-		}
-
-	}
-
-	// objects ( synchronous init of procedural primitives )
-
-	handle_objects();
-
-	// defaults
-
-	if ( result.cameras && data.defaults.camera ) {
-
-		result.currentCamera = result.cameras[ data.defaults.camera ];
-
-	}
-
-	if ( result.fogs && data.defaults.fog ) {
-
-		result.scene.fog = result.fogs[ data.defaults.fog ];
-
-	}
-
-	// synchronous callback
-
-	scope.callbackSync( result );
-
-	// just in case there are no async elements
-
-	async_callback_gate();
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.TextureLoader = function () {
-
-	this.crossOrigin = null;
-
-};
-
-THREE.TextureLoader.prototype = {
-
-	constructor: THREE.TextureLoader,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	load: function ( url ) {
-
-		var scope = this;
-
-		var image = new Image();
-
-		image.addEventListener( 'load', function () {
-
-			var texture = new THREE.Texture( image );
-			texture.needsUpdate = true;
-
-			scope.dispatchEvent( { type: 'load', content: texture } );
-
-		}, false );
-
-		image.addEventListener( 'error', function () {
-
-			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
-
-		}, false );
-
-		if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin;
-
-		image.src = url;
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Material = function () {
-
-	this.id = THREE.MaterialIdCount ++;
-
-	this.name = '';
-
-	this.side = THREE.FrontSide;
-
-	this.opacity = 1;
-	this.transparent = false;
-
-	this.blending = THREE.NormalBlending;
-
-	this.blendSrc = THREE.SrcAlphaFactor;
-	this.blendDst = THREE.OneMinusSrcAlphaFactor;
-	this.blendEquation = THREE.AddEquation;
-
-	this.depthTest = true;
-	this.depthWrite = true;
-
-	this.polygonOffset = false;
-	this.polygonOffsetFactor = 0;
-	this.polygonOffsetUnits = 0;
-
-	this.alphaTest = 0;
-
-	this.overdraw = false; // Boolean for fixing antialiasing gaps in CanvasRenderer
-
-	this.visible = true;
-
-	this.needsUpdate = true;
-
-};
-
-THREE.Material.prototype = {
-
-	constructor: THREE.Material,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	setValues: function ( values ) {
-
-		if ( values === undefined ) return;
-
-		for ( var key in values ) {
-
-			var newValue = values[ key ];
-
-			if ( newValue === undefined ) {
-
-				console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
-				continue;
-
-			}
-
-			if ( key in this ) {
-
-				var currentValue = this[ key ];
-
-				if ( currentValue instanceof THREE.Color ) {
-
-					currentValue.set( newValue );
-
-				} else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {
-
-					currentValue.copy( newValue );
-
-				} else {
-
-					this[ key ] = newValue;
-
-				}
-
-			}
-
-		}
-
-	},
-
-	clone: function ( material ) {
-
-		if ( material === undefined ) material = new THREE.Material();
-
-		material.name = this.name;
-
-		material.side = this.side;
-
-		material.opacity = this.opacity;
-		material.transparent = this.transparent;
-
-		material.blending = this.blending;
-
-		material.blendSrc = this.blendSrc;
-		material.blendDst = this.blendDst;
-		material.blendEquation = this.blendEquation;
-
-		material.depthTest = this.depthTest;
-		material.depthWrite = this.depthWrite;
-
-		material.polygonOffset = this.polygonOffset;
-		material.polygonOffsetFactor = this.polygonOffsetFactor;
-		material.polygonOffsetUnits = this.polygonOffsetUnits;
-
-		material.alphaTest = this.alphaTest;
-
-		material.overdraw = this.overdraw;
-
-		material.visible = this.visible;
-
-		return material;
-
-	},
-
-	dispose: function () {
-
-		this.dispatchEvent( { type: 'dispose' } );
-
-	}
-
-};
-
-THREE.MaterialIdCount = 0;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  opacity: <float>,
- *
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  linewidth: <float>,
- *  linecap: "round",
- *  linejoin: "round",
- *
- *  vertexColors: <bool>
- *
- *  fog: <bool>
- * }
- */
-
-THREE.LineBasicMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff );
-
-	this.linewidth = 1;
-	this.linecap = 'round';
-	this.linejoin = 'round';
-
-	this.vertexColors = false;
-
-	this.fog = true;
-
-	this.setValues( parameters );
-
-};
-
-THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.LineBasicMaterial.prototype.clone = function () {
-
-	var material = new THREE.LineBasicMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-
-	material.linewidth = this.linewidth;
-	material.linecap = this.linecap;
-	material.linejoin = this.linejoin;
-
-	material.vertexColors = this.vertexColors;
-
-	material.fog = this.fog;
-
-	return material;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  opacity: <float>,
- *
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  linewidth: <float>,
- *
- *  scale: <float>,
- *  dashSize: <float>,
- *  gapSize: <float>,
- *
- *  vertexColors: <bool>
- *
- *  fog: <bool>
- * }
- */
-
-THREE.LineDashedMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff );
-
-	this.linewidth = 1;
-
-	this.scale = 1;
-	this.dashSize = 3;
-	this.gapSize = 1;
-
-	this.vertexColors = false;
-
-	this.fog = true;
-
-	this.setValues( parameters );
-
-};
-
-THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.LineDashedMaterial.prototype.clone = function () {
-
-	var material = new THREE.LineDashedMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-
-	material.linewidth = this.linewidth;
-
-	material.scale = this.scale;
-	material.dashSize = this.dashSize;
-	material.gapSize = this.gapSize;
-
-	material.vertexColors = this.vertexColors;
-
-	material.fog = this.fog;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  opacity: <float>,
- *  map: new THREE.Texture( <Image> ),
- *
- *  lightMap: new THREE.Texture( <Image> ),
- *
- *  specularMap: new THREE.Texture( <Image> ),
- *
- *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- *  combine: THREE.Multiply,
- *  reflectivity: <float>,
- *  refractionRatio: <float>,
- *
- *  shading: THREE.SmoothShading,
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>,
- *
- *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- *  skinning: <bool>,
- *  morphTargets: <bool>,
- *
- *  fog: <bool>
- * }
- */
-
-THREE.MeshBasicMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff ); // emissive
-
-	this.map = null;
-
-	this.lightMap = null;
-
-	this.specularMap = null;
-
-	this.envMap = null;
-	this.combine = THREE.MultiplyOperation;
-	this.reflectivity = 1;
-	this.refractionRatio = 0.98;
-
-	this.fog = true;
-
-	this.shading = THREE.SmoothShading;
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-	this.wireframeLinecap = 'round';
-	this.wireframeLinejoin = 'round';
-
-	this.vertexColors = THREE.NoColors;
-
-	this.skinning = false;
-	this.morphTargets = false;
-
-	this.setValues( parameters );
-
-};
-
-THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.MeshBasicMaterial.prototype.clone = function () {
-
-	var material = new THREE.MeshBasicMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-
-	material.map = this.map;
-
-	material.lightMap = this.lightMap;
-
-	material.specularMap = this.specularMap;
-
-	material.envMap = this.envMap;
-	material.combine = this.combine;
-	material.reflectivity = this.reflectivity;
-	material.refractionRatio = this.refractionRatio;
-
-	material.fog = this.fog;
-
-	material.shading = this.shading;
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-	material.wireframeLinecap = this.wireframeLinecap;
-	material.wireframeLinejoin = this.wireframeLinejoin;
-
-	material.vertexColors = this.vertexColors;
-
-	material.skinning = this.skinning;
-	material.morphTargets = this.morphTargets;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  ambient: <hex>,
- *  emissive: <hex>,
- *  opacity: <float>,
- *
- *  map: new THREE.Texture( <Image> ),
- *
- *  lightMap: new THREE.Texture( <Image> ),
- *
- *  specularMap: new THREE.Texture( <Image> ),
- *
- *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- *  combine: THREE.Multiply,
- *  reflectivity: <float>,
- *  refractionRatio: <float>,
- *
- *  shading: THREE.SmoothShading,
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>,
- *
- *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- *  skinning: <bool>,
- *  morphTargets: <bool>,
- *  morphNormals: <bool>,
- *
- *	fog: <bool>
- * }
- */
-
-THREE.MeshLambertMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff ); // diffuse
-	this.ambient = new THREE.Color( 0xffffff );
-	this.emissive = new THREE.Color( 0x000000 );
-
-	this.wrapAround = false;
-	this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
-
-	this.map = null;
-
-	this.lightMap = null;
-
-	this.specularMap = null;
-
-	this.envMap = null;
-	this.combine = THREE.MultiplyOperation;
-	this.reflectivity = 1;
-	this.refractionRatio = 0.98;
-
-	this.fog = true;
-
-	this.shading = THREE.SmoothShading;
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-	this.wireframeLinecap = 'round';
-	this.wireframeLinejoin = 'round';
-
-	this.vertexColors = THREE.NoColors;
-
-	this.skinning = false;
-	this.morphTargets = false;
-	this.morphNormals = false;
-
-	this.setValues( parameters );
-
-};
-
-THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.MeshLambertMaterial.prototype.clone = function () {
-
-	var material = new THREE.MeshLambertMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-	material.ambient.copy( this.ambient );
-	material.emissive.copy( this.emissive );
-
-	material.wrapAround = this.wrapAround;
-	material.wrapRGB.copy( this.wrapRGB );
-
-	material.map = this.map;
-
-	material.lightMap = this.lightMap;
-
-	material.specularMap = this.specularMap;
-
-	material.envMap = this.envMap;
-	material.combine = this.combine;
-	material.reflectivity = this.reflectivity;
-	material.refractionRatio = this.refractionRatio;
-
-	material.fog = this.fog;
-
-	material.shading = this.shading;
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-	material.wireframeLinecap = this.wireframeLinecap;
-	material.wireframeLinejoin = this.wireframeLinejoin;
-
-	material.vertexColors = this.vertexColors;
-
-	material.skinning = this.skinning;
-	material.morphTargets = this.morphTargets;
-	material.morphNormals = this.morphNormals;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  ambient: <hex>,
- *  emissive: <hex>,
- *  specular: <hex>,
- *  shininess: <float>,
- *  opacity: <float>,
- *
- *  map: new THREE.Texture( <Image> ),
- *
- *  lightMap: new THREE.Texture( <Image> ),
- *
- *  bumpMap: new THREE.Texture( <Image> ),
- *  bumpScale: <float>,
- *
- *  normalMap: new THREE.Texture( <Image> ),
- *  normalScale: <Vector2>,
- *
- *  specularMap: new THREE.Texture( <Image> ),
- *
- *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- *  combine: THREE.Multiply,
- *  reflectivity: <float>,
- *  refractionRatio: <float>,
- *
- *  shading: THREE.SmoothShading,
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>,
- *
- *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- *  skinning: <bool>,
- *  morphTargets: <bool>,
- *  morphNormals: <bool>,
- *
- *	fog: <bool>
- * }
- */
-
-THREE.MeshPhongMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff ); // diffuse
-	this.ambient = new THREE.Color( 0xffffff );
-	this.emissive = new THREE.Color( 0x000000 );
-	this.specular = new THREE.Color( 0x111111 );
-	this.shininess = 30;
-
-	this.metal = false;
-	this.perPixel = true;
-
-	this.wrapAround = false;
-	this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
-
-	this.map = null;
-
-	this.lightMap = null;
-
-	this.bumpMap = null;
-	this.bumpScale = 1;
-
-	this.normalMap = null;
-	this.normalScale = new THREE.Vector2( 1, 1 );
-
-	this.specularMap = null;
-
-	this.envMap = null;
-	this.combine = THREE.MultiplyOperation;
-	this.reflectivity = 1;
-	this.refractionRatio = 0.98;
-
-	this.fog = true;
-
-	this.shading = THREE.SmoothShading;
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-	this.wireframeLinecap = 'round';
-	this.wireframeLinejoin = 'round';
-
-	this.vertexColors = THREE.NoColors;
-
-	this.skinning = false;
-	this.morphTargets = false;
-	this.morphNormals = false;
-
-	this.setValues( parameters );
-
-};
-
-THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.MeshPhongMaterial.prototype.clone = function () {
-
-	var material = new THREE.MeshPhongMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-	material.ambient.copy( this.ambient );
-	material.emissive.copy( this.emissive );
-	material.specular.copy( this.specular );
-	material.shininess = this.shininess;
-
-	material.metal = this.metal;
-	material.perPixel = this.perPixel;
-
-	material.wrapAround = this.wrapAround;
-	material.wrapRGB.copy( this.wrapRGB );
-
-	material.map = this.map;
-
-	material.lightMap = this.lightMap;
-
-	material.bumpMap = this.bumpMap;
-	material.bumpScale = this.bumpScale;
-
-	material.normalMap = this.normalMap;
-	material.normalScale.copy( this.normalScale );
-
-	material.specularMap = this.specularMap;
-
-	material.envMap = this.envMap;
-	material.combine = this.combine;
-	material.reflectivity = this.reflectivity;
-	material.refractionRatio = this.refractionRatio;
-
-	material.fog = this.fog;
-
-	material.shading = this.shading;
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-	material.wireframeLinecap = this.wireframeLinecap;
-	material.wireframeLinejoin = this.wireframeLinejoin;
-
-	material.vertexColors = this.vertexColors;
-
-	material.skinning = this.skinning;
-	material.morphTargets = this.morphTargets;
-	material.morphNormals = this.morphNormals;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  opacity: <float>,
- *
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>
- * }
- */
-
-THREE.MeshDepthMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-
-	this.setValues( parameters );
-
-};
-
-THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.MeshDepthMaterial.prototype.clone = function () {
-
-	var material = new THREE.MeshDepthMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- *
- * parameters = {
- *  opacity: <float>,
- *
- *  shading: THREE.FlatShading,
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>
- * }
- */
-
-THREE.MeshNormalMaterial = function ( parameters ) {
-
-	THREE.Material.call( this, parameters );
-
-	this.shading = THREE.FlatShading;
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-
-	this.morphTargets = false;
-
-	this.setValues( parameters );
-
-};
-
-THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.MeshNormalMaterial.prototype.clone = function () {
-
-	var material = new THREE.MeshNormalMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.shading = this.shading;
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.MeshFaceMaterial = function ( materials ) {
-
-	this.materials = materials instanceof Array ? materials : [];
-
-};
-
-THREE.MeshFaceMaterial.prototype.clone = function () {
-
-	return new THREE.MeshFaceMaterial( this.materials.slice( 0 ) );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  opacity: <float>,
- *  map: new THREE.Texture( <Image> ),
- *
- *  size: <float>,
- *
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  vertexColors: <bool>,
- *
- *  fog: <bool>
- * }
- */
-
-THREE.ParticleBasicMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff );
-
-	this.map = null;
-
-	this.size = 1;
-	this.sizeAttenuation = true;
-
-	this.vertexColors = false;
-
-	this.fog = true;
-
-	this.setValues( parameters );
-
-};
-
-THREE.ParticleBasicMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.ParticleBasicMaterial.prototype.clone = function () {
-
-	var material = new THREE.ParticleBasicMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-
-	material.map = this.map;
-
-	material.size = this.size;
-	material.sizeAttenuation = this.sizeAttenuation;
-
-	material.vertexColors = this.vertexColors;
-
-	material.fog = this.fog;
-
-	return material;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- *
- * parameters = {
- *  color: <hex>,
- *  program: <function>,
- *  opacity: <float>,
- *  blending: THREE.NormalBlending
- * }
- */
-
-THREE.ParticleCanvasMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.color = new THREE.Color( 0xffffff );
-	this.program = function ( context, color ) {};
-
-	this.setValues( parameters );
-
-};
-
-THREE.ParticleCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.ParticleCanvasMaterial.prototype.clone = function () {
-
-	var material = new THREE.ParticleCanvasMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-	material.program = this.program;
-
-	return material;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  fragmentShader: <string>,
- *  vertexShader: <string>,
- *
- *  uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
- *
- *  defines: { "label" : "value" },
- *
- *  shading: THREE.SmoothShading,
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  wireframe: <boolean>,
- *  wireframeLinewidth: <float>,
- *
- *  lights: <bool>,
- *
- *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- *  skinning: <bool>,
- *  morphTargets: <bool>,
- *  morphNormals: <bool>,
- *
- *	fog: <bool>
- * }
- */
-
-THREE.ShaderMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	this.fragmentShader = "void main() {}";
-	this.vertexShader = "void main() {}";
-	this.uniforms = {};
-	this.defines = {};
-	this.attributes = null;
-
-	this.shading = THREE.SmoothShading;
-
-	this.linewidth = 1;
-
-	this.wireframe = false;
-	this.wireframeLinewidth = 1;
-
-	this.fog = false; // set to use scene fog
-
-	this.lights = false; // set to use scene lights
-
-	this.vertexColors = THREE.NoColors; // set to use "color" attribute stream
-
-	this.skinning = false; // set to use skinning attribute streams
-
-	this.morphTargets = false; // set to use morph targets
-	this.morphNormals = false; // set to use morph normals
-
-	this.setValues( parameters );
-
-};
-
-THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.ShaderMaterial.prototype.clone = function () {
-
-	var material = new THREE.ShaderMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.fragmentShader = this.fragmentShader;
-	material.vertexShader = this.vertexShader;
-
-	material.uniforms = THREE.UniformsUtils.clone( this.uniforms );
-
-	material.attributes = this.attributes;
-	material.defines = this.defines;
-
-	material.shading = this.shading;
-
-	material.wireframe = this.wireframe;
-	material.wireframeLinewidth = this.wireframeLinewidth;
-
-	material.fog = this.fog;
-
-	material.lights = this.lights;
-
-	material.vertexColors = this.vertexColors;
-
-	material.skinning = this.skinning;
-
-	material.morphTargets = this.morphTargets;
-	material.morphNormals = this.morphNormals;
-
-	return material;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- *  color: <hex>,
- *  opacity: <float>,
- *  map: new THREE.Texture( <Image> ),
- *
- *  blending: THREE.NormalBlending,
- *  depthTest: <bool>,
- *  depthWrite: <bool>,
- *
- *  useScreenCoordinates: <bool>,
- *  sizeAttenuation: <bool>,
- *  scaleByViewport: <bool>,
- *  alignment: THREE.SpriteAlignment.center,
- *
- *	uvOffset: new THREE.Vector2(),
- *	uvScale: new THREE.Vector2(),
- *
- *  fog: <bool>
- * }
- */
-
-THREE.SpriteMaterial = function ( parameters ) {
-
-	THREE.Material.call( this );
-
-	// defaults
-
-	this.color = new THREE.Color( 0xffffff );
-	this.map = new THREE.Texture();
-
-	this.useScreenCoordinates = true;
-	this.depthTest = !this.useScreenCoordinates;
-	this.sizeAttenuation = !this.useScreenCoordinates;
-	this.scaleByViewport = !this.sizeAttenuation;
-	this.alignment = THREE.SpriteAlignment.center.clone();
-
-	this.fog = false;
-
-	this.uvOffset = new THREE.Vector2( 0, 0 );
-	this.uvScale  = new THREE.Vector2( 1, 1 );
-
-	// set parameters
-
-	this.setValues( parameters );
-
-	// override coupled defaults if not specified explicitly by parameters
-
-	parameters = parameters || {};
-
-	if ( parameters.depthTest === undefined ) this.depthTest = !this.useScreenCoordinates;
-	if ( parameters.sizeAttenuation === undefined ) this.sizeAttenuation = !this.useScreenCoordinates;
-	if ( parameters.scaleByViewport === undefined ) this.scaleByViewport = !this.sizeAttenuation;
-
-};
-
-THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype );
-
-THREE.SpriteMaterial.prototype.clone = function () {
-
-	var material = new THREE.SpriteMaterial();
-
-	THREE.Material.prototype.clone.call( this, material );
-
-	material.color.copy( this.color );
-	material.map = this.map;
-
-	material.useScreenCoordinates = this.useScreenCoordinates;
-	material.sizeAttenuation = this.sizeAttenuation;
-	material.scaleByViewport = this.scaleByViewport;
-	material.alignment.copy( this.alignment );
-
-	material.uvOffset.copy( this.uvOffset );
-	material.uvScale.copy( this.uvScale );
-
-	material.fog = this.fog;
-
-	return material;
-
-};
-
-// Alignment enums
-
-THREE.SpriteAlignment = {};
-THREE.SpriteAlignment.topLeft = new THREE.Vector2( 1, -1 );
-THREE.SpriteAlignment.topCenter = new THREE.Vector2( 0, -1 );
-THREE.SpriteAlignment.topRight = new THREE.Vector2( -1, -1 );
-THREE.SpriteAlignment.centerLeft = new THREE.Vector2( 1, 0 );
-THREE.SpriteAlignment.center = new THREE.Vector2( 0, 0 );
-THREE.SpriteAlignment.centerRight = new THREE.Vector2( -1, 0 );
-THREE.SpriteAlignment.bottomLeft = new THREE.Vector2( 1, 1 );
-THREE.SpriteAlignment.bottomCenter = new THREE.Vector2( 0, 1 );
-THREE.SpriteAlignment.bottomRight = new THREE.Vector2( -1, 1 );
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author szimek / https://github.com/szimek/
- */
-
-THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
-
-	this.id = THREE.TextureIdCount ++;
-
-	this.name = '';
-
-	this.image = image;
-	this.mipmaps = [];
-
-	this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();
-
-	this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;
-	this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;
-
-	this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
-	this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;
-
-	this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
-
-	this.format = format !== undefined ? format : THREE.RGBAFormat;
-	this.type = type !== undefined ? type : THREE.UnsignedByteType;
-
-	this.offset = new THREE.Vector2( 0, 0 );
-	this.repeat = new THREE.Vector2( 1, 1 );
-
-	this.generateMipmaps = true;
-	this.premultiplyAlpha = false;
-	this.flipY = true;
-	this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
-
-	this.needsUpdate = false;
-	this.onUpdate = null;
-
-};
-
-THREE.Texture.prototype = {
-
-	constructor: THREE.Texture,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	clone: function ( texture ) {
-
-		if ( texture === undefined ) texture = new THREE.Texture();
-
-		texture.image = this.image;
-		texture.mipmaps = this.mipmaps.slice(0);
-
-		texture.mapping = this.mapping;
-
-		texture.wrapS = this.wrapS;
-		texture.wrapT = this.wrapT;
-
-		texture.magFilter = this.magFilter;
-		texture.minFilter = this.minFilter;
-
-		texture.anisotropy = this.anisotropy;
-
-		texture.format = this.format;
-		texture.type = this.type;
-
-		texture.offset.copy( this.offset );
-		texture.repeat.copy( this.repeat );
-
-		texture.generateMipmaps = this.generateMipmaps;
-		texture.premultiplyAlpha = this.premultiplyAlpha;
-		texture.flipY = this.flipY;
-		texture.unpackAlignment = this.unpackAlignment;
-
-		return texture;
-
-	},
-
-	dispose: function () {
-
-		this.dispatchEvent( { type: 'dispose' } );
-
-	}
-
-};
-
-THREE.TextureIdCount = 0;
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
-
-	THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
-
-	this.image = { width: width, height: height };
-	this.mipmaps = mipmaps;
-
-	this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file
-
-};
-
-THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );
-
-THREE.CompressedTexture.prototype.clone = function () {
-
-	var texture = new THREE.CompressedTexture();
-
-	THREE.Texture.prototype.clone.call( this, texture );
-
-	return texture;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
-
-	THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
-
-	this.image = { data: data, width: width, height: height };
-
-};
-
-THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype );
-
-THREE.DataTexture.prototype.clone = function () {
-
-	var texture = new THREE.DataTexture();
-
-	THREE.Texture.prototype.clone.call( this, texture );
-
-	return texture;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Particle = function ( material ) {
-
-	THREE.Object3D.call( this );
-
-	this.material = material;
-
-};
-
-THREE.Particle.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Particle.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.Particle( this.material );
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.ParticleSystem = function ( geometry, material ) {
-
-	THREE.Object3D.call( this );
-
-	this.geometry = geometry;
-	this.material = ( material !== undefined ) ? material : new THREE.ParticleBasicMaterial( { color: Math.random() * 0xffffff } );
-
-	this.sortParticles = false;
-
-	if ( this.geometry ) {
-
-		// calc bound radius
-
-		if( this.geometry.boundingSphere === null ) {
-
-			this.geometry.computeBoundingSphere();
-
-		}
-
-	}
-
-	this.frustumCulled = false;
-
-};
-
-THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.ParticleSystem.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material );
-	object.sortParticles = this.sortParticles;
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Line = function ( geometry, material, type ) {
-
-	THREE.Object3D.call( this );
-
-	this.geometry = geometry;
-	this.material = ( material !== undefined ) ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );
-	this.type = ( type !== undefined ) ? type : THREE.LineStrip;
-
-	if ( this.geometry ) {
-
-		if ( ! this.geometry.boundingSphere ) {
-
-			this.geometry.computeBoundingSphere();
-
-		}
-
-	}
-
-};
-
-THREE.LineStrip = 0;
-THREE.LinePieces = 1;
-
-THREE.Line.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Line.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type );
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author mikael emtinger / http://gomo.se/
- * @author jonobr1 / http://jonobr1.com/
- */
-
-THREE.Mesh = function ( geometry, material ) {
-
-	THREE.Object3D.call( this );
-
-	this.geometry = null;
-	this.material = null;
-
-	this.setGeometry( geometry );
-	this.setMaterial( material );
-
-};
-
-THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Mesh.prototype.setGeometry = function ( geometry ) {
-
-	if ( geometry !== undefined ) {
-
-		this.geometry = geometry;
-
-		if ( this.geometry.boundingSphere === null ) {
-
-			this.geometry.computeBoundingSphere();
-
-		}
-
-		this.updateMorphTargets();
-
-	}
-
-};
-
-THREE.Mesh.prototype.setMaterial = function ( material ) {
-
-	if ( material !== undefined ) {
-
-		this.material = material;
-
-	} else {
-
-		this.material = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: true } );
-
-	}
-
-};
-
-THREE.Mesh.prototype.updateMorphTargets = function () {
-
-	if ( this.geometry.morphTargets.length > 0 ) {
-
-		this.morphTargetBase = -1;
-		this.morphTargetForcedOrder = [];
-		this.morphTargetInfluences = [];
-		this.morphTargetDictionary = {};
-
-		for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {
-
-			this.morphTargetInfluences.push( 0 );
-			this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;
-
-		}
-
-	}
-
-};
-
-THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {
-
-	if ( this.morphTargetDictionary[ name ] !== undefined ) {
-
-		return this.morphTargetDictionary[ name ];
-
-	}
-
-	console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." );
-
-	return 0;
-
-};
-
-THREE.Mesh.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Bone = function( belongsToSkin ) {
-
-	THREE.Object3D.call( this );
-
-	this.skin = belongsToSkin;
-	this.skinMatrix = new THREE.Matrix4();
-
-};
-
-THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) {
-
-	// update local
-
-	if ( this.matrixAutoUpdate ) {
-
-		forceUpdate |= this.updateMatrix();
-
-	}
-
-	// update skin matrix
-
-	if ( forceUpdate || this.matrixWorldNeedsUpdate ) {
-
-		if( parentSkinMatrix ) {
-
-			this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix );
-
-		} else {
-
-			this.skinMatrix.copy( this.matrix );
-
-		}
-
-		this.matrixWorldNeedsUpdate = false;
-		forceUpdate = true;
-
-	}
-
-	// update children
-
-	var child, i, l = this.children.length;
-
-	for ( i = 0; i < l; i ++ ) {
-
-		this.children[ i ].update( this.skinMatrix, forceUpdate );
-
-	}
-
-};
-
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
-
-	THREE.Mesh.call( this, geometry, material );
-
-	//
-
-	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
-
-	// init bones
-
-	this.identityMatrix = new THREE.Matrix4();
-
-	this.bones = [];
-	this.boneMatrices = [];
-
-	var b, bone, gbone, p, q, s;
-
-	if ( this.geometry && this.geometry.bones !== undefined ) {
-
-		for ( b = 0; b < this.geometry.bones.length; b ++ ) {
-
-			gbone = this.geometry.bones[ b ];
-
-			p = gbone.pos;
-			q = gbone.rotq;
-			s = gbone.scl;
-
-			bone = this.addBone();
-
-			bone.name = gbone.name;
-			bone.position.set( p[0], p[1], p[2] );
-			bone.quaternion.set( q[0], q[1], q[2], q[3] );
-			bone.useQuaternion = true;
-
-			if ( s !== undefined ) {
-
-				bone.scale.set( s[0], s[1], s[2] );
-
-			} else {
-
-				bone.scale.set( 1, 1, 1 );
-
-			}
-
-		}
-
-		for ( b = 0; b < this.bones.length; b ++ ) {
-
-			gbone = this.geometry.bones[ b ];
-			bone = this.bones[ b ];
-
-			if ( gbone.parent === -1 ) {
-
-				this.add( bone );
-
-			} else {
-
-				this.bones[ gbone.parent ].add( bone );
-
-			}
-
-		}
-
-		//
-
-		var nBones = this.bones.length;
-
-		if ( this.useVertexTexture ) {
-
-			// layout (1 matrix = 4 pixels)
-			//	RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
-			//  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
-			//  	 16x16 pixel texture max   64 bones (16 * 16 / 4)
-			//  	 32x32 pixel texture max  256 bones (32 * 32 / 4)
-			//  	 64x64 pixel texture max 1024 bones (64 * 64 / 4)
-
-			var size;
-
-			if ( nBones > 256 )
-				size = 64;
-			else if ( nBones > 64 )
-				size = 32;
-			else if ( nBones > 16 )
-				size = 16;
-			else
-				size = 8;
-
-			this.boneTextureWidth = size;
-			this.boneTextureHeight = size;
-
-			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
-			this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
-			this.boneTexture.minFilter = THREE.NearestFilter;
-			this.boneTexture.magFilter = THREE.NearestFilter;
-			this.boneTexture.generateMipmaps = false;
-			this.boneTexture.flipY = false;
-
-		} else {
-
-			this.boneMatrices = new Float32Array( 16 * nBones );
-
-		}
-
-		this.pose();
-
-	}
-
-};
-
-THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
-
-THREE.SkinnedMesh.prototype.addBone = function( bone ) {
-
-	if ( bone === undefined ) {
-
-		bone = new THREE.Bone( this );
-
-	}
-
-	this.bones.push( bone );
-
-	return bone;
-
-};
-
-THREE.SkinnedMesh.prototype.updateMatrixWorld = function ( force ) {
-
-	this.matrixAutoUpdate && this.updateMatrix();
-
-	// update matrixWorld
-
-	if ( this.matrixWorldNeedsUpdate || force ) {
-
-		if ( this.parent ) {
-
-			this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
-
-		} else {
-
-			this.matrixWorld.copy( this.matrix );
-
-		}
-
-		this.matrixWorldNeedsUpdate = false;
-
-		force = true;
-
-	}
-
-	// update children
-
-	for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-		var child = this.children[ i ];
-
-		if ( child instanceof THREE.Bone ) {
-
-			child.update( this.identityMatrix, false );
-
-		} else {
-
-			child.updateMatrixWorld( true );
-
-		}
-
-	}
-
-	// make a snapshot of the bones' rest position
-
-	if ( this.boneInverses == undefined ) {
-
-		this.boneInverses = [];
-
-		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
-
-			var inverse = new THREE.Matrix4();
-
-			inverse.getInverse( this.bones[ b ].skinMatrix );
-
-			this.boneInverses.push( inverse );
-
-		}
-
-	}
-
-	// flatten bone matrices to array
-
-	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
-
-		// compute the offset between the current and the original transform;
-
-		//TODO: we could get rid of this multiplication step if the skinMatrix
-		// was already representing the offset; however, this requires some
-		// major changes to the animation system
-
-		THREE.SkinnedMesh.offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] );
-
-		THREE.SkinnedMesh.offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
-
-	}
-
-	if ( this.useVertexTexture ) {
-
-		this.boneTexture.needsUpdate = true;
-
-	}
-
-};
-
-THREE.SkinnedMesh.prototype.pose = function () {
-
-	this.updateMatrixWorld( true );
-
-	for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {
-
-		// normalize weights
-
-		var sw = this.geometry.skinWeights[ i ];
-
-		var scale = 1.0 / sw.lengthManhattan();
-
-		if ( scale !== Infinity ) {
-
-			sw.multiplyScalar( scale );
-
-		} else {
-
-			sw.set( 1 ); // this will be normalized by the shader anyway
-
-		}
-
-	}
-
-};
-
-THREE.SkinnedMesh.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture );
-
-	THREE.Mesh.prototype.clone.call( this, object );
-
-	return object;
-
-};
-
-THREE.SkinnedMesh.offsetMatrix = new THREE.Matrix4();
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.MorphAnimMesh = function ( geometry, material ) {
-
-	THREE.Mesh.call( this, geometry, material );
-
-	// API
-
-	this.duration = 1000; // milliseconds
-	this.mirroredLoop = false;
-	this.time = 0;
-
-	// internals
-
-	this.lastKeyframe = 0;
-	this.currentKeyframe = 0;
-
-	this.direction = 1;
-	this.directionBackwards = false;
-
-	this.setFrameRange( 0, this.geometry.morphTargets.length - 1 );
-
-};
-
-THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );
-
-THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) {
-
-	this.startKeyframe = start;
-	this.endKeyframe = end;
-
-	this.length = this.endKeyframe - this.startKeyframe + 1;
-
-};
-
-THREE.MorphAnimMesh.prototype.setDirectionForward = function () {
-
-	this.direction = 1;
-	this.directionBackwards = false;
-
-};
-
-THREE.MorphAnimMesh.prototype.setDirectionBackward = function () {
-
-	this.direction = -1;
-	this.directionBackwards = true;
-
-};
-
-THREE.MorphAnimMesh.prototype.parseAnimations = function () {
-
-	var geometry = this.geometry;
-
-	if ( ! geometry.animations ) geometry.animations = {};
-
-	var firstAnimation, animations = geometry.animations;
-
-	var pattern = /([a-z]+)(\d+)/;
-
-	for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {
-
-		var morph = geometry.morphTargets[ i ];
-		var parts = morph.name.match( pattern );
-
-		if ( parts && parts.length > 1 ) {
-
-			var label = parts[ 1 ];
-			var num = parts[ 2 ];
-
-			if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity };
-
-			var animation = animations[ label ];
-
-			if ( i < animation.start ) animation.start = i;
-			if ( i > animation.end ) animation.end = i;
-
-			if ( ! firstAnimation ) firstAnimation = label;
-
-		}
-
-	}
-
-	geometry.firstAnimation = firstAnimation;
-
-};
-
-THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) {
-
-	if ( ! this.geometry.animations ) this.geometry.animations = {};
-
-	this.geometry.animations[ label ] = { start: start, end: end };
-
-};
-
-THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
-
-	var animation = this.geometry.animations[ label ];
-
-	if ( animation ) {
-
-		this.setFrameRange( animation.start, animation.end );
-		this.duration = 1000 * ( ( animation.end - animation.start ) / fps );
-		this.time = 0;
-
-	} else {
-
-		console.warn( "animation[" + label + "] undefined" );
-
-	}
-
-};
-
-THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) {
-
-	var frameTime = this.duration / this.length;
-
-	this.time += this.direction * delta;
-
-	if ( this.mirroredLoop ) {
-
-		if ( this.time > this.duration || this.time < 0 ) {
-
-			this.direction *= -1;
-
-			if ( this.time > this.duration ) {
-
-				this.time = this.duration;
-				this.directionBackwards = true;
-
-			}
-
-			if ( this.time < 0 ) {
-
-				this.time = 0;
-				this.directionBackwards = false;
-
-			}
-
-		}
-
-	} else {
-
-		this.time = this.time % this.duration;
-
-		if ( this.time < 0 ) this.time += this.duration;
-
-	}
-
-	var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 );
-
-	if ( keyframe !== this.currentKeyframe ) {
-
-		this.morphTargetInfluences[ this.lastKeyframe ] = 0;
-		this.morphTargetInfluences[ this.currentKeyframe ] = 1;
-
-		this.morphTargetInfluences[ keyframe ] = 0;
-
-		this.lastKeyframe = this.currentKeyframe;
-		this.currentKeyframe = keyframe;
-
-	}
-
-	var mix = ( this.time % frameTime ) / frameTime;
-
-	if ( this.directionBackwards ) {
-
-		mix = 1 - mix;
-
-	}
-
-	this.morphTargetInfluences[ this.currentKeyframe ] = mix;
-	this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix;
-
-};
-
-THREE.MorphAnimMesh.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material );
-
-	object.duration = this.duration;
-	object.mirroredLoop = this.mirroredLoop;
-	object.time = this.time;
-
-	object.lastKeyframe = this.lastKeyframe;
-	object.currentKeyframe = this.currentKeyframe;
-
-	object.direction = this.direction;
-	object.directionBackwards = this.directionBackwards;
-
-	THREE.Mesh.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Ribbon = function ( geometry, material ) {
-
-	THREE.Object3D.call( this );
-
-	this.geometry = geometry;
-	this.material = material;
-
-};
-
-THREE.Ribbon.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Ribbon.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.Ribbon( this.geometry, this.material );
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.LOD = function () {
-
-	THREE.Object3D.call( this );
-
-	this.objects = [];
-
-};
-
-
-THREE.LOD.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.LOD.prototype.addLevel = function ( object, distance ) {
-
-	if ( distance === undefined ) distance = 0;
-
-	distance = Math.abs( distance );
-
-	for ( var l = 0; l < this.objects.length; l ++ ) {
-
-		if ( distance < this.objects[ l ].distance ) {
-
-			break;
-
-		}
-
-	}
-
-	this.objects.splice( l, 0, { distance: distance, object: object } );
-	this.add( object );
-
-};
-
-THREE.LOD.prototype.getObjectForDistance = function ( distance ) {
-
-	for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
-
-		if ( distance < this.objects[ i ].distance ) {
-
-			break;
-
-		}
-
-	}
-
-	return this.objects[ i - 1 ].object;
-
-};
-
-THREE.LOD.prototype.update = function () {
-
-	var v1 = new THREE.Vector3();
-	var v2 = new THREE.Vector3();
-
-	return function ( camera ) {
-
-		if ( this.objects.length > 1 ) {
-
-			v1.getPositionFromMatrix( camera.matrixWorld );
-			v2.getPositionFromMatrix( this.matrixWorld );
-
-			var distance = v1.distanceTo( v2 );
-
-			this.objects[ 0 ].object.visible = true;
-
-			for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
-
-				if ( distance >= this.objects[ i ].distance ) {
-
-					this.objects[ i - 1 ].object.visible = false;
-					this.objects[ i     ].object.visible = true;
-
-				} else {
-
-					break;
-
-				}
-
-			}
-
-			for( ; i < l; i ++ ) {
-
-				this.objects[ i ].object.visible = false;
-
-			}
-
-		}
-
-	};
-
-}();
-
-THREE.LOD.prototype.clone = function () {
-
-	// TODO
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Sprite = function ( material ) {
-
-	THREE.Object3D.call( this );
-
-	this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial();
-
-	this.rotation3d = this.rotation;
-	this.rotation = 0;
-
-};
-
-THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );
-
-/*
- * Custom update matrix
- */
-
-THREE.Sprite.prototype.updateMatrix = function () {
-
-	this.rotation3d.set( 0, 0, this.rotation );
-	this.quaternion.setFromEuler( this.rotation3d, this.eulerOrder );
-	this.matrix.makeFromPositionQuaternionScale( this.position, this.quaternion, this.scale );
-
-	this.matrixWorldNeedsUpdate = true;
-
-};
-
-THREE.Sprite.prototype.clone = function ( object ) {
-
-	if ( object === undefined ) object = new THREE.Sprite( this.material );
-
-	THREE.Object3D.prototype.clone.call( this, object );
-
-	return object;
-
-};
-
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Scene = function () {
-
-	THREE.Object3D.call( this );
-
-	this.fog = null;
-	this.overrideMaterial = null;
-
-	this.autoUpdate = true; // checked by the renderer
-	this.matrixAutoUpdate = false;
-
-	this.__objects = [];
-	this.__lights = [];
-
-	this.__objectsAdded = [];
-	this.__objectsRemoved = [];
-
-};
-
-THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Scene.prototype.__addObject = function ( object ) {
-
-	if ( object instanceof THREE.Light ) {
-
-		if ( this.__lights.indexOf( object ) === - 1 ) {
-
-			this.__lights.push( object );
-
-		}
-
-		if ( object.target && object.target.parent === undefined ) {
-
-			this.add( object.target );
-
-		}
-
-	} else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) {
-
-		if ( this.__objects.indexOf( object ) === - 1 ) {
-
-			this.__objects.push( object );
-			this.__objectsAdded.push( object );
-
-			// check if previously removed
-
-			var i = this.__objectsRemoved.indexOf( object );
-
-			if ( i !== -1 ) {
-
-				this.__objectsRemoved.splice( i, 1 );
-
-			}
-
-		}
-
-	}
-
-	for ( var c = 0; c < object.children.length; c ++ ) {
-
-		this.__addObject( object.children[ c ] );
-
-	}
-
-};
-
-THREE.Scene.prototype.__removeObject = function ( object ) {
-
-	if ( object instanceof THREE.Light ) {
-
-		var i = this.__lights.indexOf( object );
-
-		if ( i !== -1 ) {
-
-			this.__lights.splice( i, 1 );
-
-		}
-
-	} else if ( !( object instanceof THREE.Camera ) ) {
-
-		var i = this.__objects.indexOf( object );
-
-		if( i !== -1 ) {
-
-			this.__objects.splice( i, 1 );
-			this.__objectsRemoved.push( object );
-
-			// check if previously added
-
-			var ai = this.__objectsAdded.indexOf( object );
-
-			if ( ai !== -1 ) {
-
-				this.__objectsAdded.splice( ai, 1 );
-
-			}
-
-		}
-
-	}
-
-	for ( var c = 0; c < object.children.length; c ++ ) {
-
-		this.__removeObject( object.children[ c ] );
-
-	}
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Fog = function ( hex, near, far ) {
-
-	this.name = '';
-
-	this.color = new THREE.Color( hex );
-
-	this.near = ( near !== undefined ) ? near : 1;
-	this.far = ( far !== undefined ) ? far : 1000;
-
-};
-
-THREE.Fog.prototype.clone = function () {
-
-	return new THREE.Fog( this.color.getHex(), this.near, this.far );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.FogExp2 = function ( hex, density ) {
-
-	this.name = '';
-	this.color = new THREE.Color( hex );
-	this.density = ( density !== undefined ) ? density : 0.00025;
-
-};
-
-THREE.FogExp2.prototype.clone = function () {
-
-	return new THREE.FogExp2( this.color.getHex(), this.density );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.CanvasRenderer = function ( parameters ) {
-
-	console.log( 'THREE.CanvasRenderer', THREE.REVISION );
-
-	var smoothstep = THREE.Math.smoothstep;
-
-	parameters = parameters || {};
-
-	var _this = this,
-	_renderData, _elements, _lights,
-	_projector = new THREE.Projector(),
-
-	_canvas = parameters.canvas !== undefined
-			? parameters.canvas
-			: document.createElement( 'canvas' ),
-
-	_canvasWidth, _canvasHeight, _canvasWidthHalf, _canvasHeightHalf,
-	_context = _canvas.getContext( '2d' ),
-
-	_clearColor = new THREE.Color( 0x000000 ),
-	_clearAlpha = 0,
-
-	_contextGlobalAlpha = 1,
-	_contextGlobalCompositeOperation = 0,
-	_contextStrokeStyle = null,
-	_contextFillStyle = null,
-	_contextLineWidth = null,
-	_contextLineCap = null,
-	_contextLineJoin = null,
-	_contextDashSize = null,
-	_contextGapSize = 0,
-
-	_v1, _v2, _v3, _v4,
-	_v5 = new THREE.RenderableVertex(),
-	_v6 = new THREE.RenderableVertex(),
-
-	_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
-	_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
-
-	_color = new THREE.Color(),
-	_color1 = new THREE.Color(),
-	_color2 = new THREE.Color(),
-	_color3 = new THREE.Color(),
-	_color4 = new THREE.Color(),
-
-	_diffuseColor = new THREE.Color(),
-	_emissiveColor = new THREE.Color(),
-
-	_lightColor = new THREE.Color(),
-
-	_patterns = {}, _imagedatas = {},
-
-	_near, _far,
-
-	_image, _uvs,
-	_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
-
-	_clipBox = new THREE.Box2(),
-	_clearBox = new THREE.Box2(),
-	_elemBox = new THREE.Box2(),
-
-	_ambientLight = new THREE.Color(),
-	_directionalLights = new THREE.Color(),
-	_pointLights = new THREE.Color(),
-
-	_vector3 = new THREE.Vector3(), // Needed for PointLight
-
-	_pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData,
-	_gradientMap, _gradientMapContext, _gradientMapQuality = 16;
-
-	_pixelMap = document.createElement( 'canvas' );
-	_pixelMap.width = _pixelMap.height = 2;
-
-	_pixelMapContext = _pixelMap.getContext( '2d' );
-	_pixelMapContext.fillStyle = 'rgba(0,0,0,1)';
-	_pixelMapContext.fillRect( 0, 0, 2, 2 );
-
-	_pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 );
-	_pixelMapData = _pixelMapImage.data;
-
-	_gradientMap = document.createElement( 'canvas' );
-	_gradientMap.width = _gradientMap.height = _gradientMapQuality;
-
-	_gradientMapContext = _gradientMap.getContext( '2d' );
-	_gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 );
-	_gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality );
-
-	_gradientMapQuality --; // Fix UVs
-
-	// dash+gap fallbacks for Firefox and everything else
-
-	if ( _context.setLineDash === undefined ) {
-
-		if ( _context.mozDash !== undefined ) {
-
-			_context.setLineDash = function ( values ) {
-
-				_context.mozDash = values[ 0 ] !== null ? values : null;
-
-			}
-
-		} else {
-
-			_context.setLineDash = function () {}
-
-		}
-
-	}
-
-	this.domElement = _canvas;
-
-	this.devicePixelRatio = parameters.devicePixelRatio !== undefined
-				? parameters.devicePixelRatio
-				: window.devicePixelRatio !== undefined
-					? window.devicePixelRatio
-					: 1;
-
-	this.autoClear = true;
-	this.sortObjects = true;
-	this.sortElements = true;
-
-	this.info = {
-
-		render: {
-
-			vertices: 0,
-			faces: 0
-
-		}
-
-	}
-
-	// WebGLRenderer compatibility
-
-	this.supportsVertexTextures = function () {};
-	this.setFaceCulling = function () {};
-
-	this.setSize = function ( width, height, updateStyle ) {
-
-		_canvasWidth = width * this.devicePixelRatio;
-		_canvasHeight = height * this.devicePixelRatio;
-
-		_canvasWidthHalf = Math.floor( _canvasWidth / 2 );
-		_canvasHeightHalf = Math.floor( _canvasHeight / 2 );
-
-		_canvas.width = _canvasWidth;
-		_canvas.height = _canvasHeight;
-
-		if ( this.devicePixelRatio !== 1 && updateStyle !== false ) {
-
-			_canvas.style.width = width + 'px';
-			_canvas.style.height = height + 'px';
-
-		}
-
-		_clipBox.set(
-			new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ),
-			new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf )
-		);
-
-		_clearBox.set(
-			new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ),
-			new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf )
-		);
-
-		_contextGlobalAlpha = 1;
-		_contextGlobalCompositeOperation = 0;
-		_contextStrokeStyle = null;
-		_contextFillStyle = null;
-		_contextLineWidth = null;
-		_contextLineCap = null;
-		_contextLineJoin = null;
-
-	};
-
-	this.setClearColor = function ( color, alpha ) {
-
-		_clearColor.set( color );
-		_clearAlpha = alpha !== undefined ? alpha : 1;
-
-		_clearBox.set(
-			new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ),
-			new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf )
-		);
-
-	};
-
-	this.setClearColorHex = function ( hex, alpha ) {
-
-		console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
-		this.setClearColor( hex, alpha );
-
-	};
-
-	this.getMaxAnisotropy = function () {
-
-		return 0;
-
-	};
-
-	this.clear = function () {
-
-		_context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );
-
-		if ( _clearBox.empty() === false ) {
-
-			_clearBox.intersect( _clipBox );
-			_clearBox.expandByScalar( 2 );
-
-			if ( _clearAlpha < 1 ) {
-
-				_context.clearRect(
-					_clearBox.min.x | 0,
-					_clearBox.min.y | 0,
-					( _clearBox.max.x - _clearBox.min.x ) | 0,
-					( _clearBox.max.y - _clearBox.min.y ) | 0
-				);
-
-			}
-
-			if ( _clearAlpha > 0 ) {
-
-				setBlending( THREE.NormalBlending );
-				setOpacity( 1 );
-
-				setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
-
-				_context.fillRect(
-					_clearBox.min.x | 0,
-					_clearBox.min.y | 0,
-					( _clearBox.max.x - _clearBox.min.x ) | 0,
-					( _clearBox.max.y - _clearBox.min.y ) | 0
-				);
-
-			}
-
-			_clearBox.makeEmpty();
-
-		}
-
-
-	};
-
-	this.render = function ( scene, camera ) {
-
-		if ( camera instanceof THREE.Camera === false ) {
-
-			console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
-			return;
-
-		}
-
-		if ( this.autoClear === true ) this.clear();
-
-		_context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );
-
-		_this.info.render.vertices = 0;
-		_this.info.render.faces = 0;
-
-		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
-		_elements = _renderData.elements;
-		_lights = _renderData.lights;
-
-		/* DEBUG
-		setFillStyle( 'rgba( 0, 255, 255, 0.5 )' );
-		_context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y );
-		*/
-
-		calculateLights();
-
-		for ( var e = 0, el = _elements.length; e < el; e++ ) {
-
-			var element = _elements[ e ];
-
-			var material = element.material;
-
-			if ( material === undefined || material.visible === false ) continue;
-
-			_elemBox.makeEmpty();
-
-			if ( element instanceof THREE.RenderableParticle ) {
-
-				_v1 = element;
-				_v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
-
-				renderParticle( _v1, element, material );
-
-			} else if ( element instanceof THREE.RenderableLine ) {
-
-				_v1 = element.v1; _v2 = element.v2;
-
-				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
-				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
-
-				_elemBox.setFromPoints( [
-					_v1.positionScreen,
-					_v2.positionScreen
-				] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderLine( _v1, _v2, element, material );
-
-				}
-
-			} else if ( element instanceof THREE.RenderableFace3 ) {
-
-				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
-
-				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
-				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
-				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;
-
-				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
-				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
-				_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
-
-				if ( material.overdraw === true ) {
-
-					expand( _v1.positionScreen, _v2.positionScreen );
-					expand( _v2.positionScreen, _v3.positionScreen );
-					expand( _v3.positionScreen, _v1.positionScreen );
-
-				}
-
-				_elemBox.setFromPoints( [
-					_v1.positionScreen,
-					_v2.positionScreen,
-					_v3.positionScreen
-				] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );
-
-				}
-
-			} else if ( element instanceof THREE.RenderableFace4 ) {
-
-				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3; _v4 = element.v4;
-
-				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
-				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
-				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;
-				if ( _v4.positionScreen.z < -1 || _v4.positionScreen.z > 1 ) continue;
-
-				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
-				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
-				_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
-				_v4.positionScreen.x *= _canvasWidthHalf; _v4.positionScreen.y *= _canvasHeightHalf;
-
-				_v5.positionScreen.copy( _v2.positionScreen );
-				_v6.positionScreen.copy( _v4.positionScreen );
-
-				if ( material.overdraw === true ) {
-
-					expand( _v1.positionScreen, _v2.positionScreen );
-					expand( _v2.positionScreen, _v4.positionScreen );
-					expand( _v4.positionScreen, _v1.positionScreen );
-
-					expand( _v3.positionScreen, _v5.positionScreen );
-					expand( _v3.positionScreen, _v6.positionScreen );
-
-				}
-
-				_elemBox.setFromPoints( [
-					_v1.positionScreen,
-					_v2.positionScreen,
-					_v3.positionScreen,
-					_v4.positionScreen
-				] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderFace4( _v1, _v2, _v3, _v4, _v5, _v6, element, material );
-
-				}
-
-			}
-
-			/* DEBUG
-			setLineWidth( 1 );
-			setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' );
-			_context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y );
-			*/
-
-			_clearBox.union( _elemBox );
-
-		}
-
-		/* DEBUG
-		setLineWidth( 1 );
-		setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' );
-		_context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y );
-		*/
-
-		_context.setTransform( 1, 0, 0, 1, 0, 0 );
-
-		//
-
-		function calculateLights() {
-
-			_ambientLight.setRGB( 0, 0, 0 );
-			_directionalLights.setRGB( 0, 0, 0 );
-			_pointLights.setRGB( 0, 0, 0 );
-
-			for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
-
-				var light = _lights[ l ];
-				var lightColor = light.color;
-
-				if ( light instanceof THREE.AmbientLight ) {
-
-					_ambientLight.add( lightColor );
-
-				} else if ( light instanceof THREE.DirectionalLight ) {
-
-					// for particles
-
-					_directionalLights.add( lightColor );
-
-				} else if ( light instanceof THREE.PointLight ) {
-
-					// for particles
-
-					_pointLights.add( lightColor );
-
-				}
-
-			}
-
-		}
-
-		function calculateLight( position, normal, color ) {
-
-			for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
-
-				var light = _lights[ l ];
-
-				_lightColor.copy( light.color );
-
-				if ( light instanceof THREE.DirectionalLight ) {
-
-					var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ).normalize();
-
-					var amount = normal.dot( lightPosition );
-
-					if ( amount <= 0 ) continue;
-
-					amount *= light.intensity;
-
-					color.add( _lightColor.multiplyScalar( amount ) );
-
-				} else if ( light instanceof THREE.PointLight ) {
-
-					var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld );
-
-					var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
-
-					if ( amount <= 0 ) continue;
-
-					amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
-
-					if ( amount == 0 ) continue;
-
-					amount *= light.intensity;
-
-					color.add( _lightColor.multiplyScalar( amount ) );
-
-				}
-
-			}
-
-		}
-
-		function renderParticle( v1, element, material ) {
-
-			setOpacity( material.opacity );
-			setBlending( material.blending );
-
-			var width, height, scaleX, scaleY,
-			bitmap, bitmapWidth, bitmapHeight;
-
-			if ( material instanceof THREE.ParticleBasicMaterial ) {
-
-				if ( material.map === null ) {
-
-					scaleX = element.object.scale.x;
-					scaleY = element.object.scale.y;
-
-					// TODO: Be able to disable this
-
-					scaleX *= element.scale.x * _canvasWidthHalf;
-					scaleY *= element.scale.y * _canvasHeightHalf;
-
-					_elemBox.min.set( v1.x - scaleX, v1.y - scaleY );
-					_elemBox.max.set( v1.x + scaleX, v1.y + scaleY );
-
-					if ( _clipBox.isIntersectionBox( _elemBox ) === false ) {
-
-						_elemBox.makeEmpty();
-						return;
-
-					}
-
-					setFillStyle( material.color.getStyle() );
-
-					_context.save();
-					_context.translate( v1.x, v1.y );
-					_context.rotate( - element.rotation );
-					_context.scale( scaleX, scaleY );
-					_context.fillRect( -1, -1, 2, 2 );
-					_context.restore();
-
-				} else {
-
-					bitmap = material.map.image;
-					bitmapWidth = bitmap.width >> 1;
-					bitmapHeight = bitmap.height >> 1;
-
-					scaleX = element.scale.x * _canvasWidthHalf;
-					scaleY = element.scale.y * _canvasHeightHalf;
-
-					width = scaleX * bitmapWidth;
-					height = scaleY * bitmapHeight;
-
-					// TODO: Rotations break this...
-
-					_elemBox.min.set( v1.x - width, v1.y - height );
-					_elemBox.max.set( v1.x + width, v1.y + height );
-
-					if ( _clipBox.isIntersectionBox( _elemBox ) === false ) {
-
-						_elemBox.makeEmpty();
-						return;
-
-					}
-
-					_context.save();
-					_context.translate( v1.x, v1.y );
-					_context.rotate( - element.rotation );
-					_context.scale( scaleX, - scaleY );
-
-					_context.translate( - bitmapWidth, - bitmapHeight );
-					_context.drawImage( bitmap, 0, 0 );
-					_context.restore();
-
-				}
-
-				/* DEBUG
-				setStrokeStyle( 'rgb(255,255,0)' );
-				_context.beginPath();
-				_context.moveTo( v1.x - 10, v1.y );
-				_context.lineTo( v1.x + 10, v1.y );
-				_context.moveTo( v1.x, v1.y - 10 );
-				_context.lineTo( v1.x, v1.y + 10 );
-				_context.stroke();
-				*/
-
-			} else if ( material instanceof THREE.ParticleCanvasMaterial ) {
-
-				width = element.scale.x * _canvasWidthHalf;
-				height = element.scale.y * _canvasHeightHalf;
-
-				_elemBox.min.set( v1.x - width, v1.y - height );
-				_elemBox.max.set( v1.x + width, v1.y + height );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === false ) {
-
-					_elemBox.makeEmpty();
-					return;
-
-				}
-
-				setStrokeStyle( material.color.getStyle() );
-				setFillStyle( material.color.getStyle() );
-
-				_context.save();
-				_context.translate( v1.x, v1.y );
-				_context.rotate( - element.rotation );
-				_context.scale( width, height );
-
-				material.program( _context );
-
-				_context.restore();
-
-			}
-
-		}
-
-		function renderLine( v1, v2, element, material ) {
-
-			setOpacity( material.opacity );
-			setBlending( material.blending );
-
-			_context.beginPath();
-			_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
-			_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
-
-			if ( material instanceof THREE.LineBasicMaterial ) {
-
-				setLineWidth( material.linewidth );
-				setLineCap( material.linecap );
-				setLineJoin( material.linejoin );
-
-				if ( material.vertexColors !== THREE.VertexColors ) {
-
-					setStrokeStyle( material.color.getStyle() );
-
-				} else {
-
-					var colorStyle1 = element.vertexColors[0].getStyle();
-					var colorStyle2 = element.vertexColors[1].getStyle();
-
-					if ( colorStyle1 === colorStyle2 ) {
-
-						setStrokeStyle( colorStyle1 );
-
-					} else {
-
-						try {
-
-							var grad = _context.createLinearGradient(
-								v1.positionScreen.x,
-								v1.positionScreen.y,
-								v2.positionScreen.x,
-								v2.positionScreen.y
-							);
-							grad.addColorStop( 0, colorStyle1 );
-							grad.addColorStop( 1, colorStyle2 );
-
-						} catch ( exception ) {
-
-							grad = colorStyle1;
-
-						}
-
-						setStrokeStyle( grad );
-
-					}
-
-				}
-
-				_context.stroke();
-				_elemBox.expandByScalar( material.linewidth * 2 );
-
-			} else if ( material instanceof THREE.LineDashedMaterial ) {
-
-				setLineWidth( material.linewidth );
-				setLineCap( material.linecap );
-				setLineJoin( material.linejoin );
-				setStrokeStyle( material.color.getStyle() );
-				setDashAndGap( material.dashSize, material.gapSize );
-
-				_context.stroke();
-
-				_elemBox.expandByScalar( material.linewidth * 2 );
-
-				setDashAndGap( null, null );
-
-			}
-
-		}
-
-		function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {
-
-			_this.info.render.vertices += 3;
-			_this.info.render.faces ++;
-
-			setOpacity( material.opacity );
-			setBlending( material.blending );
-
-			_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
-			_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
-			_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
-
-			drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
-
-			if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
-
-				_diffuseColor.copy( material.color );
-				_emissiveColor.copy( material.emissive );
-
-				if ( material.vertexColors === THREE.FaceColors ) {
-
-					_diffuseColor.multiply( element.color );
-
-				}
-
-				if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 3 ) {
-
-					_color1.copy( _ambientLight );
-					_color2.copy( _ambientLight );
-					_color3.copy( _ambientLight );
-
-					calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 );
-					calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 );
-					calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 );
-
-					_color1.multiply( _diffuseColor ).add( _emissiveColor );
-					_color2.multiply( _diffuseColor ).add( _emissiveColor );
-					_color3.multiply( _diffuseColor ).add( _emissiveColor );
-					_color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 );
-
-					_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-					clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );
-
-				} else {
-
-					_color.copy( _ambientLight );
-
-					calculateLight( element.centroidModel, element.normalModel, _color );
-
-					_color.multiply( _diffuseColor ).add( _emissiveColor );
-
-					material.wireframe === true
-						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-						: fillPath( _color );
-
-				}
-
-			} else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
-
-				if ( material.map !== null ) {
-
-					if ( material.map.mapping instanceof THREE.UVMapping ) {
-
-						_uvs = element.uvs[ 0 ];
-						patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map );
-
-					}
-
-
-				} else if ( material.envMap !== null ) {
-
-					if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) {
-
-						_vector3.copy( element.vertexNormalsModelView[ uv1 ] );
-						_uv1x = 0.5 * _vector3.x + 0.5;
-						_uv1y = 0.5 * _vector3.y + 0.5;
-
-						_vector3.copy( element.vertexNormalsModelView[ uv2 ] );
-						_uv2x = 0.5 * _vector3.x + 0.5;
-						_uv2y = 0.5 * _vector3.y + 0.5;
-
-						_vector3.copy( element.vertexNormalsModelView[ uv3 ] );
-						_uv3x = 0.5 * _vector3.x + 0.5;
-						_uv3y = 0.5 * _vector3.y + 0.5;
-
-						patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
-
-					}/* else if ( material.envMap.mapping == THREE.SphericalRefractionMapping ) {
-
-
-
-					}*/
-
-
-				} else {
-
-					_color.copy( material.color );
-
-					if ( material.vertexColors === THREE.FaceColors ) {
-
-						_color.multiply( element.color );
-
-					}
-
-					material.wireframe === true
-						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-						: fillPath( _color );
-
-				}
-
-			} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-				_near = camera.near;
-				_far = camera.far;
-
-				_color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far );
-				_color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far );
-				_color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far );
-				_color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 );
-
-				_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-				clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );
-
-			} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-				var normal;
-
-				if ( material.shading == THREE.FlatShading ) {
-
-					normal = element.normalModelView;
-
-					_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					material.wireframe === true
-						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-						: fillPath( _color );
-
-				} else if ( material.shading == THREE.SmoothShading ) {
-
-					normal = element.vertexNormalsModelView[ uv1 ];
-					_color1.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					normal = element.vertexNormalsModelView[ uv2 ];
-					_color2.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					normal = element.vertexNormalsModelView[ uv3 ];
-					_color3.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					_color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 );
-
-					_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-					clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );
-
-				}
-
-			}
-
-		}
-
-		function renderFace4( v1, v2, v3, v4, v5, v6, element, material ) {
-
-			_this.info.render.vertices += 4;
-			_this.info.render.faces ++;
-
-			setOpacity( material.opacity );
-			setBlending( material.blending );
-
-			if ( ( material.map !== undefined && material.map !== null ) || ( material.envMap !== undefined && material.envMap !== null ) ) {
-
-				// Let renderFace3() handle this
-
-				renderFace3( v1, v2, v4, 0, 1, 3, element, material );
-				renderFace3( v5, v3, v6, 1, 2, 3, element, material );
-
-				return;
-
-			}
-
-			_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
-			_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
-			_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
-			_v4x = v4.positionScreen.x; _v4y = v4.positionScreen.y;
-			_v5x = v5.positionScreen.x; _v5y = v5.positionScreen.y;
-			_v6x = v6.positionScreen.x; _v6y = v6.positionScreen.y;
-
-			if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
-
-				_diffuseColor.copy( material.color );
-				_emissiveColor.copy( material.emissive );
-
-				if ( material.vertexColors === THREE.FaceColors ) {
-
-					_diffuseColor.multiply( element.color );
-
-				}
-
-				if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 4 ) {
-
-					_color1.copy( _ambientLight );
-					_color2.copy( _ambientLight );
-					_color3.copy( _ambientLight );
-					_color4.copy( _ambientLight );
-
-					calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 );
-					calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 );
-					calculateLight( element.v4.positionWorld, element.vertexNormalsModel[ 3 ], _color3 );
-					calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color4 );
-
-					_color1.multiply( _diffuseColor ).add( _emissiveColor );
-					_color2.multiply( _diffuseColor ).add( _emissiveColor );
-					_color3.multiply( _diffuseColor ).add( _emissiveColor );
-					_color4.multiply( _diffuseColor ).add( _emissiveColor );
-
-					_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-					// TODO: UVs are incorrect, v4->v3?
-
-					drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
-					clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );
-
-					drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
-					clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );
-
-				} else {
-
-					_color.copy( _ambientLight );
-
-					calculateLight( element.centroidModel, element.normalModel, _color );
-
-					_color.multiply( _diffuseColor ).add( _emissiveColor );
-
-					drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
-
-					material.wireframe === true
-						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-						: fillPath( _color );
-
-				}
-
-			} else if ( material instanceof THREE.MeshBasicMaterial ) {
-
-				_color.copy( material.color );
-
-				if ( material.vertexColors === THREE.FaceColors ) {
-
-					_color.multiply( element.color );
-
-				}
-
-				drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
-
-				material.wireframe === true
-					? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-					: fillPath( _color );
-
-			} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-				var normal;
-
-				if ( material.shading == THREE.FlatShading ) {
-
-					normal = element.normalModelView;
-					_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
-
-					material.wireframe === true
-						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-						: fillPath( _color );
-
-				} else if ( material.shading == THREE.SmoothShading ) {
-
-					normal = element.vertexNormalsModelView[ 0 ];
-					_color1.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					normal = element.vertexNormalsModelView[ 1 ];
-					_color2.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					normal = element.vertexNormalsModelView[ 3 ];
-					_color3.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					normal = element.vertexNormalsModelView[ 2 ];
-					_color4.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-					_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-					drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
-					clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );
-
-					drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
-					clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );
-
-				}
-
-			} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-				_near = camera.near;
-				_far = camera.far;
-
-				_color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far );
-				_color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far );
-				_color3.r = _color3.g = _color3.b = 1 - smoothstep( v4.positionScreen.z * v4.positionScreen.w, _near, _far );
-				_color4.r = _color4.g = _color4.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far );
-
-				_image = getGradientTexture( _color1, _color2, _color3, _color4 );
-
-				// TODO: UVs are incorrect, v4->v3?
-
-				drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
-				clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );
-
-				drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
-				clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );
-
-			}
-
-		}
-
-		//
-
-		function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
-
-			_context.beginPath();
-			_context.moveTo( x0, y0 );
-			_context.lineTo( x1, y1 );
-			_context.lineTo( x2, y2 );
-			_context.closePath();
-
-		}
-
-		function drawQuad( x0, y0, x1, y1, x2, y2, x3, y3 ) {
-
-			_context.beginPath();
-			_context.moveTo( x0, y0 );
-			_context.lineTo( x1, y1 );
-			_context.lineTo( x2, y2 );
-			_context.lineTo( x3, y3 );
-			_context.closePath();
-
-		}
-
-		function strokePath( color, linewidth, linecap, linejoin ) {
-
-			setLineWidth( linewidth );
-			setLineCap( linecap );
-			setLineJoin( linejoin );
-			setStrokeStyle( color.getStyle() );
-
-			_context.stroke();
-
-			_elemBox.expandByScalar( linewidth * 2 );
-
-		}
-
-		function fillPath( color ) {
-
-			setFillStyle( color.getStyle() );
-			_context.fill();
-
-		}
-
-		function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
-
-			if ( texture instanceof THREE.DataTexture || texture.image === undefined || texture.image.width == 0 ) return;
-
-			if ( texture.needsUpdate === true ) {
-
-				var repeatX = texture.wrapS == THREE.RepeatWrapping;
-				var repeatY = texture.wrapT == THREE.RepeatWrapping;
-
-				_patterns[ texture.id ] = _context.createPattern(
-					texture.image, repeatX === true && repeatY === true
-						? 'repeat'
-						: repeatX === true && repeatY === false
-							? 'repeat-x'
-							: repeatX === false && repeatY === true
-								? 'repeat-y'
-								: 'no-repeat'
-				);
-
-				texture.needsUpdate = false;
-
-			}
-
-			_patterns[ texture.id ] === undefined
-				? setFillStyle( 'rgba(0,0,0,1)' )
-				: setFillStyle( _patterns[ texture.id ] );
-
-			// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
-
-			var a, b, c, d, e, f, det, idet,
-			offsetX = texture.offset.x / texture.repeat.x,
-			offsetY = texture.offset.y / texture.repeat.y,
-			width = texture.image.width * texture.repeat.x,
-			height = texture.image.height * texture.repeat.y;
-
-			u0 = ( u0 + offsetX ) * width;
-			v0 = ( 1.0 - v0 + offsetY ) * height;
-
-			u1 = ( u1 + offsetX ) * width;
-			v1 = ( 1.0 - v1 + offsetY ) * height;
-
-			u2 = ( u2 + offsetX ) * width;
-			v2 = ( 1.0 - v2 + offsetY ) * height;
-
-			x1 -= x0; y1 -= y0;
-			x2 -= x0; y2 -= y0;
-
-			u1 -= u0; v1 -= v0;
-			u2 -= u0; v2 -= v0;
-
-			det = u1 * v2 - u2 * v1;
-
-			if ( det === 0 ) {
-
-				if ( _imagedatas[ texture.id ] === undefined ) {
-
-					var canvas = document.createElement( 'canvas' )
-					canvas.width = texture.image.width;
-					canvas.height = texture.image.height;
-
-					var context = canvas.getContext( '2d' );
-					context.drawImage( texture.image, 0, 0 );
-
-					_imagedatas[ texture.id ] = context.getImageData( 0, 0, texture.image.width, texture.image.height ).data;
-
-				}
-
-				var data = _imagedatas[ texture.id ];
-				var index = ( Math.floor( u0 ) + Math.floor( v0 ) * texture.image.width ) * 4;
-
-				_color.setRGB( data[ index ] / 255, data[ index + 1 ] / 255, data[ index + 2 ] / 255 );
-				fillPath( _color );
-
-				return;
-
-			}
-
-			idet = 1 / det;
-
-			a = ( v2 * x1 - v1 * x2 ) * idet;
-			b = ( v2 * y1 - v1 * y2 ) * idet;
-			c = ( u1 * x2 - u2 * x1 ) * idet;
-			d = ( u1 * y2 - u2 * y1 ) * idet;
-
-			e = x0 - a * u0 - c * v0;
-			f = y0 - b * u0 - d * v0;
-
-			_context.save();
-			_context.transform( a, b, c, d, e, f );
-			_context.fill();
-			_context.restore();
-
-		}
-
-		function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
-
-			// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
-
-			var a, b, c, d, e, f, det, idet,
-			width = image.width - 1,
-			height = image.height - 1;
-
-			u0 *= width; v0 *= height;
-			u1 *= width; v1 *= height;
-			u2 *= width; v2 *= height;
-
-			x1 -= x0; y1 -= y0;
-			x2 -= x0; y2 -= y0;
-
-			u1 -= u0; v1 -= v0;
-			u2 -= u0; v2 -= v0;
-
-			det = u1 * v2 - u2 * v1;
-
-			idet = 1 / det;
-
-			a = ( v2 * x1 - v1 * x2 ) * idet;
-			b = ( v2 * y1 - v1 * y2 ) * idet;
-			c = ( u1 * x2 - u2 * x1 ) * idet;
-			d = ( u1 * y2 - u2 * y1 ) * idet;
-
-			e = x0 - a * u0 - c * v0;
-			f = y0 - b * u0 - d * v0;
-
-			_context.save();
-			_context.transform( a, b, c, d, e, f );
-			_context.clip();
-			_context.drawImage( image, 0, 0 );
-			_context.restore();
-
-		}
-
-		function getGradientTexture( color1, color2, color3, color4 ) {
-
-			// http://mrdoob.com/blog/post/710
-
-			_pixelMapData[ 0 ] = ( color1.r * 255 ) | 0;
-			_pixelMapData[ 1 ] = ( color1.g * 255 ) | 0;
-			_pixelMapData[ 2 ] = ( color1.b * 255 ) | 0;
-
-			_pixelMapData[ 4 ] = ( color2.r * 255 ) | 0;
-			_pixelMapData[ 5 ] = ( color2.g * 255 ) | 0;
-			_pixelMapData[ 6 ] = ( color2.b * 255 ) | 0;
-
-			_pixelMapData[ 8 ] = ( color3.r * 255 ) | 0;
-			_pixelMapData[ 9 ] = ( color3.g * 255 ) | 0;
-			_pixelMapData[ 10 ] = ( color3.b * 255 ) | 0;
-
-			_pixelMapData[ 12 ] = ( color4.r * 255 ) | 0;
-			_pixelMapData[ 13 ] = ( color4.g * 255 ) | 0;
-			_pixelMapData[ 14 ] = ( color4.b * 255 ) | 0;
-
-			_pixelMapContext.putImageData( _pixelMapImage, 0, 0 );
-			_gradientMapContext.drawImage( _pixelMap, 0, 0 );
-
-			return _gradientMap;
-
-		}
-
-		// Hide anti-alias gaps
-
-		function expand( v1, v2 ) {
-
-			var x = v2.x - v1.x, y = v2.y - v1.y,
-			det = x * x + y * y, idet;
-
-			if ( det === 0 ) return;
-
-			idet = 1 / Math.sqrt( det );
-
-			x *= idet; y *= idet;
-
-			v2.x += x; v2.y += y;
-			v1.x -= x; v1.y -= y;
-
-		}
-	};
-
-	// Context cached methods.
-
-	function setOpacity( value ) {
-
-		if ( _contextGlobalAlpha !== value ) {
-
-			_context.globalAlpha = value;
-			_contextGlobalAlpha = value;
-
-		}
-
-	}
-
-	function setBlending( value ) {
-
-		if ( _contextGlobalCompositeOperation !== value ) {
-
-			if ( value === THREE.NormalBlending ) {
-
-				_context.globalCompositeOperation = 'source-over';
-
-			} else if ( value === THREE.AdditiveBlending ) {
-
-				_context.globalCompositeOperation = 'lighter';
-
-			} else if ( value === THREE.SubtractiveBlending ) {
-
-				_context.globalCompositeOperation = 'darker';
-
-			}
-
-			_contextGlobalCompositeOperation = value;
-
-		}
-
-	}
-
-	function setLineWidth( value ) {
-
-		if ( _contextLineWidth !== value ) {
-
-			_context.lineWidth = value;
-			_contextLineWidth = value;
-
-		}
-
-	}
-
-	function setLineCap( value ) {
-
-		// "butt", "round", "square"
-
-		if ( _contextLineCap !== value ) {
-
-			_context.lineCap = value;
-			_contextLineCap = value;
-
-		}
-
-	}
-
-	function setLineJoin( value ) {
-
-		// "round", "bevel", "miter"
-
-		if ( _contextLineJoin !== value ) {
-
-			_context.lineJoin = value;
-			_contextLineJoin = value;
-
-		}
-
-	}
-
-	function setStrokeStyle( value ) {
-
-		if ( _contextStrokeStyle !== value ) {
-
-			_context.strokeStyle = value;
-			_contextStrokeStyle = value;
-
-		}
-
-	}
-
-	function setFillStyle( value ) {
-
-		if ( _contextFillStyle !== value ) {
-
-			_context.fillStyle = value;
-			_contextFillStyle = value;
-
-		}
-
-	}
-
-	function setDashAndGap( dashSizeValue, gapSizeValue ) {
-
-		if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) {
-
-			_context.setLineDash( [ dashSizeValue, gapSizeValue ] );
-			_contextDashSize = dashSizeValue;
-			_contextGapSize = gapSizeValue;
-
-		}
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author mikael emtinger / http://gomo.se/
- */
-
-THREE.ShaderChunk = {
-
-	// FOG
-
-	fog_pars_fragment: [
-
-		"#ifdef USE_FOG",
-
-			"uniform vec3 fogColor;",
-
-			"#ifdef FOG_EXP2",
-
-				"uniform float fogDensity;",
-
-			"#else",
-
-				"uniform float fogNear;",
-				"uniform float fogFar;",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	fog_fragment: [
-
-		"#ifdef USE_FOG",
-
-			"float depth = gl_FragCoord.z / gl_FragCoord.w;",
-
-			"#ifdef FOG_EXP2",
-
-				"const float LOG2 = 1.442695;",
-				"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
-				"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
-
-			"#else",
-
-				"float fogFactor = smoothstep( fogNear, fogFar, depth );",
-
-			"#endif",
-
-			"gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
-
-		"#endif"
-
-	].join("\n"),
-
-	// ENVIRONMENT MAP
-
-	envmap_pars_fragment: [
-
-		"#ifdef USE_ENVMAP",
-
-			"uniform float reflectivity;",
-			"uniform samplerCube envMap;",
-			"uniform float flipEnvMap;",
-			"uniform int combine;",
-
-			"#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
-
-				"uniform bool useRefract;",
-				"uniform float refractionRatio;",
-
-			"#else",
-
-				"varying vec3 vReflect;",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_fragment: [
-
-		"#ifdef USE_ENVMAP",
-
-			"vec3 reflectVec;",
-
-			"#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
-
-				"vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
-
-				"if ( useRefract ) {",
-
-					"reflectVec = refract( cameraToVertex, normal, refractionRatio );",
-
-				"} else { ",
-
-					"reflectVec = reflect( cameraToVertex, normal );",
-
-				"}",
-
-			"#else",
-
-				"reflectVec = vReflect;",
-
-			"#endif",
-
-			"#ifdef DOUBLE_SIDED",
-
-				"float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
-				"vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
-
-			"#else",
-
-				"vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
-
-			"#endif",
-
-			"#ifdef GAMMA_INPUT",
-
-				"cubeColor.xyz *= cubeColor.xyz;",
-
-			"#endif",
-
-			"if ( combine == 1 ) {",
-
-				"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );",
-
-			"} else if ( combine == 2 ) {",
-
-				"gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;",
-
-			"} else {",
-
-				"gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_pars_vertex: [
-
-		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
-
-			"varying vec3 vReflect;",
-
-			"uniform float refractionRatio;",
-			"uniform bool useRefract;",
-
-		"#endif"
-
-	].join("\n"),
-
-	worldpos_vertex : [
-
-		"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )",
-
-			"#ifdef USE_SKINNING",
-
-				"vec4 worldPosition = modelMatrix * skinned;",
-
-			"#endif",
-
-			"#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
-
-				"vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );",
-
-			"#endif",
-
-			"#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
-
-				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_vertex : [
-
-		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
-
-			"vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;",
-			"worldNormal = normalize( worldNormal );",
-
-			"vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );",
-
-			"if ( useRefract ) {",
-
-				"vReflect = refract( cameraToVertex, worldNormal, refractionRatio );",
-
-			"} else {",
-
-				"vReflect = reflect( cameraToVertex, worldNormal );",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// COLOR MAP (particles)
-
-	map_particle_pars_fragment: [
-
-		"#ifdef USE_MAP",
-
-			"uniform sampler2D map;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	map_particle_fragment: [
-
-		"#ifdef USE_MAP",
-
-			"gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );",
-
-		"#endif"
-
-	].join("\n"),
-
-	// COLOR MAP (triangles)
-
-	map_pars_vertex: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
-
-			"varying vec2 vUv;",
-			"uniform vec4 offsetRepeat;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_pars_fragment: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
-
-			"varying vec2 vUv;",
-
-		"#endif",
-
-		"#ifdef USE_MAP",
-
-			"uniform sampler2D map;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_vertex: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",
-
-			"vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_fragment: [
-
-		"#ifdef USE_MAP",
-
-			"vec4 texelColor = texture2D( map, vUv );",
-
-			"#ifdef GAMMA_INPUT",
-
-				"texelColor.xyz *= texelColor.xyz;",
-
-			"#endif",
-
-			"gl_FragColor = gl_FragColor * texelColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHT MAP
-
-	lightmap_pars_fragment: [
-
-		"#ifdef USE_LIGHTMAP",
-
-			"varying vec2 vUv2;",
-			"uniform sampler2D lightMap;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_pars_vertex: [
-
-		"#ifdef USE_LIGHTMAP",
-
-			"varying vec2 vUv2;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_fragment: [
-
-		"#ifdef USE_LIGHTMAP",
-
-			"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_vertex: [
-
-		"#ifdef USE_LIGHTMAP",
-
-			"vUv2 = uv2;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// BUMP MAP
-
-	bumpmap_pars_fragment: [
-
-		"#ifdef USE_BUMPMAP",
-
-			"uniform sampler2D bumpMap;",
-			"uniform float bumpScale;",
-
-			// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
-			//	http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html
-
-			// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
-
-			"vec2 dHdxy_fwd() {",
-
-				"vec2 dSTdx = dFdx( vUv );",
-				"vec2 dSTdy = dFdy( vUv );",
-
-				"float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
-				"float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
-				"float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
-
-				"return vec2( dBx, dBy );",
-
-			"}",
-
-			"vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
-
-				"vec3 vSigmaX = dFdx( surf_pos );",
-				"vec3 vSigmaY = dFdy( surf_pos );",
-				"vec3 vN = surf_norm;",		// normalized
-
-				"vec3 R1 = cross( vSigmaY, vN );",
-				"vec3 R2 = cross( vN, vSigmaX );",
-
-				"float fDet = dot( vSigmaX, R1 );",
-
-				"vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
-				"return normalize( abs( fDet ) * surf_norm - vGrad );",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// NORMAL MAP
-
-	normalmap_pars_fragment: [
-
-		"#ifdef USE_NORMALMAP",
-
-			"uniform sampler2D normalMap;",
-			"uniform vec2 normalScale;",
-
-			// Per-Pixel Tangent Space Normal Mapping
-			// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
-
-			"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {",
-
-				"vec3 q0 = dFdx( eye_pos.xyz );",
-				"vec3 q1 = dFdy( eye_pos.xyz );",
-				"vec2 st0 = dFdx( vUv.st );",
-				"vec2 st1 = dFdy( vUv.st );",
-
-				"vec3 S = normalize(  q0 * st1.t - q1 * st0.t );",
-				"vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
-				"vec3 N = normalize( surf_norm );",
-
-				"vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;",
-				"mapN.xy = normalScale * mapN.xy;",
-				"mat3 tsn = mat3( S, T, N );",
-				"return normalize( tsn * mapN );",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// SPECULAR MAP
-
-	specularmap_pars_fragment: [
-
-		"#ifdef USE_SPECULARMAP",
-
-			"uniform sampler2D specularMap;",
-
-		"#endif"
-
-	].join("\n"),
-
-	specularmap_fragment: [
-
-		"float specularStrength;",
-
-		"#ifdef USE_SPECULARMAP",
-
-			"vec4 texelSpecular = texture2D( specularMap, vUv );",
-			"specularStrength = texelSpecular.r;",
-
-		"#else",
-
-			"specularStrength = 1.0;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHTS LAMBERT
-
-	lights_lambert_pars_vertex: [
-
-		"uniform vec3 ambient;",
-		"uniform vec3 diffuse;",
-		"uniform vec3 emissive;",
-
-		"uniform vec3 ambientLightColor;",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-			"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-			"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-			"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
-			"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
-			"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-			"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-			"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
-			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-			"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
-
-		"#endif",
-
-		"#ifdef WRAP_AROUND",
-
-			"uniform vec3 wrapRGB;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lights_lambert_vertex: [
-
-		"vLightFront = vec3( 0.0 );",
-
-		"#ifdef DOUBLE_SIDED",
-
-			"vLightBack = vec3( 0.0 );",
-
-		"#endif",
-
-		"transformedNormal = normalize( transformedNormal );",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
-
-			"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-			"vec3 dirVector = normalize( lDirection.xyz );",
-
-			"float dotProduct = dot( transformedNormal, dirVector );",
-			"vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-			"#ifdef DOUBLE_SIDED",
-
-				"vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-				"#ifdef WRAP_AROUND",
-
-					"vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-				"#endif",
-
-			"#endif",
-
-			"#ifdef WRAP_AROUND",
-
-				"vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-				"directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",
-
-				"#ifdef DOUBLE_SIDED",
-
-					"directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",
-
-				"#endif",
-
-			"#endif",
-
-			"vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",
-
-			"#ifdef DOUBLE_SIDED",
-
-				"vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",
-
-			"#endif",
-
-		"}",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-				"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-				"float lDistance = 1.0;",
-				"if ( pointLightDistance[ i ] > 0.0 )",
-					"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-				"lVector = normalize( lVector );",
-				"float dotProduct = dot( transformedNormal, lVector );",
-
-				"vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-				"#ifdef DOUBLE_SIDED",
-
-					"vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-					"#ifdef WRAP_AROUND",
-
-						"vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-					"#endif",
-
-				"#endif",
-
-				"#ifdef WRAP_AROUND",
-
-					"vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-					"pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );",
-
-					"#ifdef DOUBLE_SIDED",
-
-						"pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );",
-
-					"#endif",
-
-				"#endif",
-
-				"vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;",
-
-				"#ifdef DOUBLE_SIDED",
-
-					"vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;",
-
-				"#endif",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-				"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-				"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );",
-
-				"if ( spotEffect > spotLightAngleCos[ i ] ) {",
-
-					"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
-
-					"float lDistance = 1.0;",
-					"if ( spotLightDistance[ i ] > 0.0 )",
-						"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-					"lVector = normalize( lVector );",
-
-					"float dotProduct = dot( transformedNormal, lVector );",
-					"vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-					"#ifdef DOUBLE_SIDED",
-
-						"vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-						"#ifdef WRAP_AROUND",
-
-							"vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-						"#endif",
-
-					"#endif",
-
-					"#ifdef WRAP_AROUND",
-
-						"vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-						"spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );",
-
-						"#ifdef DOUBLE_SIDED",
-
-							"spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );",
-
-						"#endif",
-
-					"#endif",
-
-					"vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;",
-
-					"#ifdef DOUBLE_SIDED",
-
-						"vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;",
-
-					"#endif",
-
-				"}",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-			"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
-
-				"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-				"vec3 lVector = normalize( lDirection.xyz );",
-
-				"float dotProduct = dot( transformedNormal, lVector );",
-
-				"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
-				"float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;",
-
-				"vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
-
-				"#ifdef DOUBLE_SIDED",
-
-					"vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );",
-
-				"#endif",
-
-			"}",
-
-		"#endif",
-
-		"vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;",
-
-		"#ifdef DOUBLE_SIDED",
-
-			"vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHTS PHONG
-
-	lights_phong_pars_vertex: [
-
-		"#ifndef PHONG_PER_PIXEL",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-			"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-			"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-
-			"varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",
-
-		"#endif",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
-
-			"varying vec3 vWorldPosition;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	lights_phong_vertex: [
-
-		"#ifndef PHONG_PER_PIXEL",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-				"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-				"float lDistance = 1.0;",
-				"if ( pointLightDistance[ i ] > 0.0 )",
-					"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-				"vPointLight[ i ] = vec4( lVector, lDistance );",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-				"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-				"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-				"float lDistance = 1.0;",
-				"if ( spotLightDistance[ i ] > 0.0 )",
-					"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-				"vSpotLight[ i ] = vec4( lVector, lDistance );",
-
-			"}",
-
-		"#endif",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
-
-			"vWorldPosition = worldPosition.xyz;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lights_phong_pars_fragment: [
-
-		"uniform vec3 ambientLightColor;",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-			"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-			"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-			"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
-			"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
-			"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-
-			"#ifdef PHONG_PER_PIXEL",
-
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-			"#else",
-
-				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
-
-			"#endif",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
-			"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-			"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
-			"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
-
-			"#ifdef PHONG_PER_PIXEL",
-
-				"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-
-			"#else",
-
-				"varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",
-
-			"#endif",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",
-
-			"varying vec3 vWorldPosition;",
-
-		"#endif",
-
-		"#ifdef WRAP_AROUND",
-
-			"uniform vec3 wrapRGB;",
-
-		"#endif",
-
-		"varying vec3 vViewPosition;",
-		"varying vec3 vNormal;"
-
-	].join("\n"),
-
-	lights_phong_fragment: [
-
-		"vec3 normal = normalize( vNormal );",
-		"vec3 viewPosition = normalize( vViewPosition );",
-
-		"#ifdef DOUBLE_SIDED",
-
-			"normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
-
-		"#endif",
-
-		"#ifdef USE_NORMALMAP",
-
-			"normal = perturbNormal2Arb( -vViewPosition, normal );",
-
-		"#elif defined( USE_BUMPMAP )",
-
-			"normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"vec3 pointDiffuse  = vec3( 0.0 );",
-			"vec3 pointSpecular = vec3( 0.0 );",
-
-			"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-				"#ifdef PHONG_PER_PIXEL",
-
-					"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-					"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-					"float lDistance = 1.0;",
-					"if ( pointLightDistance[ i ] > 0.0 )",
-						"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-					"lVector = normalize( lVector );",
-
-				"#else",
-
-					"vec3 lVector = normalize( vPointLight[ i ].xyz );",
-					"float lDistance = vPointLight[ i ].w;",
-
-				"#endif",
-
-				// diffuse
-
-				"float dotProduct = dot( normal, lVector );",
-
-				"#ifdef WRAP_AROUND",
-
-					"float pointDiffuseWeightFull = max( dotProduct, 0.0 );",
-					"float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-					"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
-
-				"#else",
-
-					"float pointDiffuseWeight = max( dotProduct, 0.0 );",
-
-				"#endif",
-
-				"pointDiffuse  += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;",
-
-				// specular
-
-				"vec3 pointHalfVector = normalize( lVector + viewPosition );",
-				"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
-				"float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
-
-				"#ifdef PHYSICALLY_BASED_SHADING",
-
-					// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-					"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
-
-					"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );",
-					"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;",
-
-				"#else",
-
-					"pointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;",
-
-				"#endif",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"vec3 spotDiffuse  = vec3( 0.0 );",
-			"vec3 spotSpecular = vec3( 0.0 );",
-
-			"for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-				"#ifdef PHONG_PER_PIXEL",
-
-					"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-					"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-					"float lDistance = 1.0;",
-					"if ( spotLightDistance[ i ] > 0.0 )",
-						"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-					"lVector = normalize( lVector );",
-
-				"#else",
-
-					"vec3 lVector = normalize( vSpotLight[ i ].xyz );",
-					"float lDistance = vSpotLight[ i ].w;",
-
-				"#endif",
-
-				"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
-
-				"if ( spotEffect > spotLightAngleCos[ i ] ) {",
-
-					"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
-
-					// diffuse
-
-					"float dotProduct = dot( normal, lVector );",
-
-					"#ifdef WRAP_AROUND",
-
-						"float spotDiffuseWeightFull = max( dotProduct, 0.0 );",
-						"float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-						"vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
-
-					"#else",
-
-						"float spotDiffuseWeight = max( dotProduct, 0.0 );",
-
-					"#endif",
-
-					"spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;",
-
-					// specular
-
-					"vec3 spotHalfVector = normalize( lVector + viewPosition );",
-					"float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
-					"float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );",
-
-					"#ifdef PHYSICALLY_BASED_SHADING",
-
-						// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-						"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
-
-						"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );",
-						"spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;",
-
-					"#else",
-
-						"spotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;",
-
-					"#endif",
-
-				"}",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-			"vec3 dirDiffuse  = vec3( 0.0 );",
-			"vec3 dirSpecular = vec3( 0.0 );" ,
-
-			"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
-
-				"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-				"vec3 dirVector = normalize( lDirection.xyz );",
-
-				// diffuse
-
-				"float dotProduct = dot( normal, dirVector );",
-
-				"#ifdef WRAP_AROUND",
-
-					"float dirDiffuseWeightFull = max( dotProduct, 0.0 );",
-					"float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-					"vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );",
-
-				"#else",
-
-					"float dirDiffuseWeight = max( dotProduct, 0.0 );",
-
-				"#endif",
-
-				"dirDiffuse  += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;",
-
-				// specular
-
-				"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
-				"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
-				"float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );",
-
-				"#ifdef PHYSICALLY_BASED_SHADING",
-
-					/*
-					// fresnel term from skin shader
-					"const float F0 = 0.128;",
-
-					"float base = 1.0 - dot( viewPosition, dirHalfVector );",
-					"float exponential = pow( base, 5.0 );",
-
-					"float fresnel = exponential + F0 * ( 1.0 - exponential );",
-					*/
-
-					/*
-					// fresnel term from fresnel shader
-					"const float mFresnelBias = 0.08;",
-					"const float mFresnelScale = 0.3;",
-					"const float mFresnelPower = 5.0;",
-
-					"float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );",
-					*/
-
-					// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-					"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
-
-					//"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;",
-
-					"vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
-					"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
-
-				"#else",
-
-					"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;",
-
-				"#endif",
-
-			"}",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-			"vec3 hemiDiffuse  = vec3( 0.0 );",
-			"vec3 hemiSpecular = vec3( 0.0 );" ,
-
-			"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
-
-				"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-				"vec3 lVector = normalize( lDirection.xyz );",
-
-				// diffuse
-
-				"float dotProduct = dot( normal, lVector );",
-				"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
-
-				"vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
-
-				"hemiDiffuse += diffuse * hemiColor;",
-
-				// specular (sky light)
-
-				"vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
-				"float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
-				"float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );",
-
-				// specular (ground light)
-
-				"vec3 lVectorGround = -lVector;",
-
-				"vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
-				"float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
-				"float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );",
-
-				"#ifdef PHYSICALLY_BASED_SHADING",
-
-					"float dotProductGround = dot( normal, lVectorGround );",
-
-					// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-					"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
-
-					"vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
-					"vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
-					"hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
-
-				"#else",
-
-					"hemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",
-
-				"#endif",
-
-			"}",
-
-		"#endif",
-
-		"vec3 totalDiffuse = vec3( 0.0 );",
-		"vec3 totalSpecular = vec3( 0.0 );",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-			"totalDiffuse += dirDiffuse;",
-			"totalSpecular += dirSpecular;",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-			"totalDiffuse += hemiDiffuse;",
-			"totalSpecular += hemiSpecular;",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-			"totalDiffuse += pointDiffuse;",
-			"totalSpecular += pointSpecular;",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-			"totalDiffuse += spotDiffuse;",
-			"totalSpecular += spotSpecular;",
-
-		"#endif",
-
-		"#ifdef METAL",
-
-			"gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );",
-
-		"#else",
-
-			"gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// VERTEX COLORS
-
-	color_pars_fragment: [
-
-		"#ifdef USE_COLOR",
-
-			"varying vec3 vColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	color_fragment: [
-
-		"#ifdef USE_COLOR",
-
-			"gl_FragColor = gl_FragColor * vec4( vColor, opacity );",
-
-		"#endif"
-
-	].join("\n"),
-
-	color_pars_vertex: [
-
-		"#ifdef USE_COLOR",
-
-			"varying vec3 vColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	color_vertex: [
-
-		"#ifdef USE_COLOR",
-
-			"#ifdef GAMMA_INPUT",
-
-				"vColor = color * color;",
-
-			"#else",
-
-				"vColor = color;",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	// SKINNING
-
-	skinning_pars_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-			"#ifdef BONE_TEXTURE",
-
-				"uniform sampler2D boneTexture;",
-
-				"mat4 getBoneMatrix( const in float i ) {",
-
-					"float j = i * 4.0;",
-					"float x = mod( j, N_BONE_PIXEL_X );",
-					"float y = floor( j / N_BONE_PIXEL_X );",
-
-					"const float dx = 1.0 / N_BONE_PIXEL_X;",
-					"const float dy = 1.0 / N_BONE_PIXEL_Y;",
-
-					"y = dy * ( y + 0.5 );",
-
-					"vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
-					"vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
-					"vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
-					"vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
-
-					"mat4 bone = mat4( v1, v2, v3, v4 );",
-
-					"return bone;",
-
-				"}",
-
-			"#else",
-
-				"uniform mat4 boneGlobalMatrices[ MAX_BONES ];",
-
-				"mat4 getBoneMatrix( const in float i ) {",
-
-					"mat4 bone = boneGlobalMatrices[ int(i) ];",
-					"return bone;",
-
-				"}",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinbase_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-			"mat4 boneMatX = getBoneMatrix( skinIndex.x );",
-			"mat4 boneMatY = getBoneMatrix( skinIndex.y );",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinning_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-			"#ifdef USE_MORPHTARGETS",
-
-			"vec4 skinVertex = vec4( morphed, 1.0 );",
-
-			"#else",
-
-			"vec4 skinVertex = vec4( position, 1.0 );",
-
-			"#endif",
-
-			"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
-			"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// MORPHING
-
-	morphtarget_pars_vertex: [
-
-		"#ifdef USE_MORPHTARGETS",
-
-			"#ifndef USE_MORPHNORMALS",
-
-			"uniform float morphTargetInfluences[ 8 ];",
-
-			"#else",
-
-			"uniform float morphTargetInfluences[ 4 ];",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	morphtarget_vertex: [
-
-		"#ifdef USE_MORPHTARGETS",
-
-			"vec3 morphed = vec3( 0.0 );",
-			"morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];",
-			"morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];",
-			"morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];",
-			"morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];",
-
-			"#ifndef USE_MORPHNORMALS",
-
-			"morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];",
-			"morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];",
-			"morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];",
-			"morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];",
-
-			"#endif",
-
-			"morphed += position;",
-
-		"#endif"
-
-	].join("\n"),
-
-	default_vertex : [
-
-		"vec4 mvPosition;",
-
-		"#ifdef USE_SKINNING",
-
-			"mvPosition = modelViewMatrix * skinned;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )",
-
-			"mvPosition = modelViewMatrix * vec4( morphed, 1.0 );",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )",
-
-			"mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-		"#endif",
-
-		"gl_Position = projectionMatrix * mvPosition;"
-
-	].join("\n"),
-
-	morphnormal_vertex: [
-
-		"#ifdef USE_MORPHNORMALS",
-
-			"vec3 morphedNormal = vec3( 0.0 );",
-
-			"morphedNormal +=  ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];",
-			"morphedNormal +=  ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];",
-			"morphedNormal +=  ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];",
-			"morphedNormal +=  ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];",
-
-			"morphedNormal += normal;",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinnormal_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-			"mat4 skinMatrix = skinWeight.x * boneMatX;",
-			"skinMatrix 	+= skinWeight.y * boneMatY;",
-
-			"#ifdef USE_MORPHNORMALS",
-
-			"vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );",
-
-			"#else",
-
-			"vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );",
-
-			"#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	defaultnormal_vertex: [
-
-		"vec3 objectNormal;",
-
-		"#ifdef USE_SKINNING",
-
-			"objectNormal = skinnedNormal.xyz;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )",
-
-			"objectNormal = morphedNormal;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )",
-
-			"objectNormal = normal;",
-
-		"#endif",
-
-		"#ifdef FLIP_SIDED",
-
-			"objectNormal = -objectNormal;",
-
-		"#endif",
-
-		"vec3 transformedNormal = normalMatrix * objectNormal;"
-
-	].join("\n"),
-
-	// SHADOW MAP
-
-	// based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples
-	//  http://spidergl.org/example.php?id=6
-	// 	http://fabiensanglard.net/shadowmapping
-
-	shadowmap_pars_fragment: [
-
-		"#ifdef USE_SHADOWMAP",
-
-			"uniform sampler2D shadowMap[ MAX_SHADOWS ];",
-			"uniform vec2 shadowMapSize[ MAX_SHADOWS ];",
-
-			"uniform float shadowDarkness[ MAX_SHADOWS ];",
-			"uniform float shadowBias[ MAX_SHADOWS ];",
-
-			"varying vec4 vShadowCoord[ MAX_SHADOWS ];",
-
-			"float unpackDepth( const in vec4 rgba_depth ) {",
-
-				"const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
-				"float depth = dot( rgba_depth, bit_shift );",
-				"return depth;",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_fragment: [
-
-		"#ifdef USE_SHADOWMAP",
-
-			"#ifdef SHADOWMAP_DEBUG",
-
-				"vec3 frustumColors[3];",
-				"frustumColors[0] = vec3( 1.0, 0.5, 0.0 );",
-				"frustumColors[1] = vec3( 0.0, 1.0, 0.8 );",
-				"frustumColors[2] = vec3( 0.0, 0.5, 1.0 );",
-
-			"#endif",
-
-			"#ifdef SHADOWMAP_CASCADE",
-
-				"int inFrustumCount = 0;",
-
-			"#endif",
-
-			"float fDepth;",
-			"vec3 shadowColor = vec3( 1.0 );",
-
-			"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
-
-				"vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;",
-
-				// "if ( something && something )" 		 breaks ATI OpenGL shader compiler
-				// "if ( all( something, something ) )"  using this instead
-
-				"bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );",
-				"bool inFrustum = all( inFrustumVec );",
-
-				// don't shadow pixels outside of light frustum
-				// use just first frustum (for cascades)
-				// don't shadow pixels behind far plane of light frustum
-
-				"#ifdef SHADOWMAP_CASCADE",
-
-					"inFrustumCount += int( inFrustum );",
-					"bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );",
-
-				"#else",
-
-					"bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );",
-
-				"#endif",
-
-				"bool frustumTest = all( frustumTestVec );",
-
-				"if ( frustumTest ) {",
-
-					"shadowCoord.z += shadowBias[ i ];",
-
-					"#if defined( SHADOWMAP_TYPE_PCF )",
-
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
-
-						"float shadow = 0.0;",
-
-						/*
-						// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
-						// must enroll loop manually
-
-						"for ( float y = -1.25; y <= 1.25; y += 1.25 )",
-							"for ( float x = -1.25; x <= 1.25; x += 1.25 ) {",
-
-								"vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );",
-
-								// doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup
-								//"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );",
-
-								"float fDepth = unpackDepth( rgbaDepth );",
-
-								"if ( fDepth < shadowCoord.z )",
-									"shadow += 1.0;",
-
-						"}",
-
-						"shadow /= 9.0;",
-
-						*/
-
-						"const float shadowDelta = 1.0 / 9.0;",
-
-						"float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
-						"float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
-
-						"float dx0 = -1.25 * xPixelOffset;",
-						"float dy0 = -1.25 * yPixelOffset;",
-						"float dx1 = 1.25 * xPixelOffset;",
-						"float dy1 = 1.25 * yPixelOffset;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
-						"if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-						"shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
-
-					"#elif defined( SHADOWMAP_TYPE_PCF_SOFT )",
-
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
-
-						"float shadow = 0.0;",
-
-						"float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
-						"float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
-
-						"float dx0 = -1.0 * xPixelOffset;",
-						"float dy0 = -1.0 * yPixelOffset;",
-						"float dx1 = 1.0 * xPixelOffset;",
-						"float dy1 = 1.0 * yPixelOffset;",
-
-						"mat3 shadowKernel;",
-						"mat3 depthKernel;",
-
-						"depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
-						"depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
-						"depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
-						"depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
-						"depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
-						"depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
-						"depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
-						"depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
-						"depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
-
-						"vec3 shadowZ = vec3( shadowCoord.z );",
-						"shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));",
-						"shadowKernel[0] *= vec3(0.25);",
-													
-						"shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));",
-						"shadowKernel[1] *= vec3(0.25);",
-
-						"shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));",
-						"shadowKernel[2] *= vec3(0.25);",
-
-						"vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );",
-
-						"shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );",
-						"shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );",
-
-						"vec4 shadowValues;",
-						"shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );",
-						"shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );",
-						"shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );",
-						"shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );",
-
-						"shadow = dot( shadowValues, vec4( 1.0 ) );",
-
-						"shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
-
-					"#else",
-
-						"vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );",
-						"float fDepth = unpackDepth( rgbaDepth );",
-
-						"if ( fDepth < shadowCoord.z )",
-
-							// spot with multiple shadows is darker
-
-							"shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );",
-
-							// spot with multiple shadows has the same color as single shadow spot
-
-							//"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );",
-
-					"#endif",
-
-				"}",
-
-
-				"#ifdef SHADOWMAP_DEBUG",
-
-					"#ifdef SHADOWMAP_CASCADE",
-
-						"if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];",
-
-					"#else",
-
-						"if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];",
-
-					"#endif",
-
-				"#endif",
-
-			"}",
-
-			"#ifdef GAMMA_OUTPUT",
-
-				"shadowColor *= shadowColor;",
-
-			"#endif",
-
-			"gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_pars_vertex: [
-
-		"#ifdef USE_SHADOWMAP",
-
-			"varying vec4 vShadowCoord[ MAX_SHADOWS ];",
-			"uniform mat4 shadowMatrix[ MAX_SHADOWS ];",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_vertex: [
-
-		"#ifdef USE_SHADOWMAP",
-
-			"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
-
-				"vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
-
-			"}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// ALPHATEST
-
-	alphatest_fragment: [
-
-		"#ifdef ALPHATEST",
-
-			"if ( gl_FragColor.a < ALPHATEST ) discard;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LINEAR SPACE
-
-	linear_to_gamma_fragment: [
-
-		"#ifdef GAMMA_OUTPUT",
-
-			"gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
-
-		"#endif"
-
-	].join("\n")
-
-
-};
-
-THREE.UniformsUtils = {
-
-	merge: function ( uniforms ) {
-
-		var u, p, tmp, merged = {};
-
-		for ( u = 0; u < uniforms.length; u ++ ) {
-
-			tmp = this.clone( uniforms[ u ] );
-
-			for ( p in tmp ) {
-
-				merged[ p ] = tmp[ p ];
-
-			}
-
-		}
-
-		return merged;
-
-	},
-
-	clone: function ( uniforms_src ) {
-
-		var u, p, parameter, parameter_src, uniforms_dst = {};
-
-		for ( u in uniforms_src ) {
-
-			uniforms_dst[ u ] = {};
-
-			for ( p in uniforms_src[ u ] ) {
-
-				parameter_src = uniforms_src[ u ][ p ];
-
-				if ( parameter_src instanceof THREE.Color ||
-					 parameter_src instanceof THREE.Vector2 ||
-					 parameter_src instanceof THREE.Vector3 ||
-					 parameter_src instanceof THREE.Vector4 ||
-					 parameter_src instanceof THREE.Matrix4 ||
-					 parameter_src instanceof THREE.Texture ) {
-
-					uniforms_dst[ u ][ p ] = parameter_src.clone();
-
-				} else if ( parameter_src instanceof Array ) {
-
-					uniforms_dst[ u ][ p ] = parameter_src.slice();
-
-				} else {
-
-					uniforms_dst[ u ][ p ] = parameter_src;
-
-				}
-
-			}
-
-		}
-
-		return uniforms_dst;
-
-	}
-
-};
-
-THREE.UniformsLib = {
-
-	common: {
-
-		"diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
-		"opacity" : { type: "f", value: 1.0 },
-
-		"map" : { type: "t", value: null },
-		"offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },
-
-		"lightMap" : { type: "t", value: null },
-		"specularMap" : { type: "t", value: null },
-
-		"envMap" : { type: "t", value: null },
-		"flipEnvMap" : { type: "f", value: -1 },
-		"useRefract" : { type: "i", value: 0 },
-		"reflectivity" : { type: "f", value: 1.0 },
-		"refractionRatio" : { type: "f", value: 0.98 },
-		"combine" : { type: "i", value: 0 },
-
-		"morphTargetInfluences" : { type: "f", value: 0 }
-
-	},
-
-	bump: {
-
-		"bumpMap" : { type: "t", value: null },
-		"bumpScale" : { type: "f", value: 1 }
-
-	},
-
-	normalmap: {
-
-		"normalMap" : { type: "t", value: null },
-		"normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }
-	},
-
-	fog : {
-
-		"fogDensity" : { type: "f", value: 0.00025 },
-		"fogNear" : { type: "f", value: 1 },
-		"fogFar" : { type: "f", value: 2000 },
-		"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
-
-	},
-
-	lights: {
-
-		"ambientLightColor" : { type: "fv", value: [] },
-
-		"directionalLightDirection" : { type: "fv", value: [] },
-		"directionalLightColor" : { type: "fv", value: [] },
-
-		"hemisphereLightDirection" : { type: "fv", value: [] },
-		"hemisphereLightSkyColor" : { type: "fv", value: [] },
-		"hemisphereLightGroundColor" : { type: "fv", value: [] },
-
-		"pointLightColor" : { type: "fv", value: [] },
-		"pointLightPosition" : { type: "fv", value: [] },
-		"pointLightDistance" : { type: "fv1", value: [] },
-
-		"spotLightColor" : { type: "fv", value: [] },
-		"spotLightPosition" : { type: "fv", value: [] },
-		"spotLightDirection" : { type: "fv", value: [] },
-		"spotLightDistance" : { type: "fv1", value: [] },
-		"spotLightAngleCos" : { type: "fv1", value: [] },
-		"spotLightExponent" : { type: "fv1", value: [] }
-
-	},
-
-	particle: {
-
-		"psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
-		"opacity" : { type: "f", value: 1.0 },
-		"size" : { type: "f", value: 1.0 },
-		"scale" : { type: "f", value: 1.0 },
-		"map" : { type: "t", value: null },
-
-		"fogDensity" : { type: "f", value: 0.00025 },
-		"fogNear" : { type: "f", value: 1 },
-		"fogFar" : { type: "f", value: 2000 },
-		"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
-
-	},
-
-	shadowmap: {
-
-		"shadowMap": { type: "tv", value: [] },
-		"shadowMapSize": { type: "v2v", value: [] },
-
-		"shadowBias" : { type: "fv1", value: [] },
-		"shadowDarkness": { type: "fv1", value: [] },
-
-		"shadowMatrix" : { type: "m4v", value: [] }
-
-	}
-
-};
-
-THREE.ShaderLib = {
-
-	'basic': {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "common" ],
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "shadowmap" ]
-
-		] ),
-
-		vertexShader: [
-
-			THREE.ShaderChunk[ "map_pars_vertex" ],
-			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
-			THREE.ShaderChunk[ "envmap_pars_vertex" ],
-			THREE.ShaderChunk[ "color_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "map_vertex" ],
-				THREE.ShaderChunk[ "lightmap_vertex" ],
-				THREE.ShaderChunk[ "color_vertex" ],
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-
-				"#ifdef USE_ENVMAP",
-
-				THREE.ShaderChunk[ "morphnormal_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-				THREE.ShaderChunk[ "defaultnormal_vertex" ],
-
-				"#endif",
-
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "skinning_vertex" ],
-				THREE.ShaderChunk[ "default_vertex" ],
-
-				THREE.ShaderChunk[ "worldpos_vertex" ],
-				THREE.ShaderChunk[ "envmap_vertex" ],
-				THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec3 diffuse;",
-			"uniform float opacity;",
-
-			THREE.ShaderChunk[ "color_pars_fragment" ],
-			THREE.ShaderChunk[ "map_pars_fragment" ],
-			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
-			THREE.ShaderChunk[ "envmap_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( diffuse, opacity );",
-
-				THREE.ShaderChunk[ "map_fragment" ],
-				THREE.ShaderChunk[ "alphatest_fragment" ],
-				THREE.ShaderChunk[ "specularmap_fragment" ],
-				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
-				THREE.ShaderChunk[ "envmap_fragment" ],
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'lambert': {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "common" ],
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-			THREE.UniformsLib[ "shadowmap" ],
-
-			{
-				"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
-				"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
-				"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
-			}
-
-		] ),
-
-		vertexShader: [
-
-			"#define LAMBERT",
-
-			"varying vec3 vLightFront;",
-
-			"#ifdef DOUBLE_SIDED",
-
-				"varying vec3 vLightBack;",
-
-			"#endif",
-
-			THREE.ShaderChunk[ "map_pars_vertex" ],
-			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
-			THREE.ShaderChunk[ "envmap_pars_vertex" ],
-			THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
-			THREE.ShaderChunk[ "color_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "map_vertex" ],
-				THREE.ShaderChunk[ "lightmap_vertex" ],
-				THREE.ShaderChunk[ "color_vertex" ],
-
-				THREE.ShaderChunk[ "morphnormal_vertex" ],
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-				THREE.ShaderChunk[ "defaultnormal_vertex" ],
-
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "skinning_vertex" ],
-				THREE.ShaderChunk[ "default_vertex" ],
-
-				THREE.ShaderChunk[ "worldpos_vertex" ],
-				THREE.ShaderChunk[ "envmap_vertex" ],
-				THREE.ShaderChunk[ "lights_lambert_vertex" ],
-				THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-
-			"varying vec3 vLightFront;",
-
-			"#ifdef DOUBLE_SIDED",
-
-				"varying vec3 vLightBack;",
-
-			"#endif",
-
-			THREE.ShaderChunk[ "color_pars_fragment" ],
-			THREE.ShaderChunk[ "map_pars_fragment" ],
-			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
-			THREE.ShaderChunk[ "envmap_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
-
-				THREE.ShaderChunk[ "map_fragment" ],
-				THREE.ShaderChunk[ "alphatest_fragment" ],
-				THREE.ShaderChunk[ "specularmap_fragment" ],
-
-				"#ifdef DOUBLE_SIDED",
-
-					//"float isFront = float( gl_FrontFacing );",
-					//"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",
-
-					"if ( gl_FrontFacing )",
-						"gl_FragColor.xyz *= vLightFront;",
-					"else",
-						"gl_FragColor.xyz *= vLightBack;",
-
-				"#else",
-
-					"gl_FragColor.xyz *= vLightFront;",
-
-				"#endif",
-
-				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
-				THREE.ShaderChunk[ "envmap_fragment" ],
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'phong': {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "common" ],
-			THREE.UniformsLib[ "bump" ],
-			THREE.UniformsLib[ "normalmap" ],
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-			THREE.UniformsLib[ "shadowmap" ],
-
-			{
-				"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
-				"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
-				"specular" : { type: "c", value: new THREE.Color( 0x111111 ) },
-				"shininess": { type: "f", value: 30 },
-				"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
-			}
-
-		] ),
-
-		vertexShader: [
-
-			"#define PHONG",
-
-			"varying vec3 vViewPosition;",
-			"varying vec3 vNormal;",
-
-			THREE.ShaderChunk[ "map_pars_vertex" ],
-			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
-			THREE.ShaderChunk[ "envmap_pars_vertex" ],
-			THREE.ShaderChunk[ "lights_phong_pars_vertex" ],
-			THREE.ShaderChunk[ "color_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "map_vertex" ],
-				THREE.ShaderChunk[ "lightmap_vertex" ],
-				THREE.ShaderChunk[ "color_vertex" ],
-
-				THREE.ShaderChunk[ "morphnormal_vertex" ],
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-				THREE.ShaderChunk[ "defaultnormal_vertex" ],
-
-				"vNormal = normalize( transformedNormal );",
-
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "skinning_vertex" ],
-				THREE.ShaderChunk[ "default_vertex" ],
-
-				"vViewPosition = -mvPosition.xyz;",
-
-				THREE.ShaderChunk[ "worldpos_vertex" ],
-				THREE.ShaderChunk[ "envmap_vertex" ],
-				THREE.ShaderChunk[ "lights_phong_vertex" ],
-				THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec3 diffuse;",
-			"uniform float opacity;",
-
-			"uniform vec3 ambient;",
-			"uniform vec3 emissive;",
-			"uniform vec3 specular;",
-			"uniform float shininess;",
-
-			THREE.ShaderChunk[ "color_pars_fragment" ],
-			THREE.ShaderChunk[ "map_pars_fragment" ],
-			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
-			THREE.ShaderChunk[ "envmap_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
-			THREE.ShaderChunk[ "normalmap_pars_fragment" ],
-			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
-
-				THREE.ShaderChunk[ "map_fragment" ],
-				THREE.ShaderChunk[ "alphatest_fragment" ],
-				THREE.ShaderChunk[ "specularmap_fragment" ],
-
-				THREE.ShaderChunk[ "lights_phong_fragment" ],
-
-				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
-				THREE.ShaderChunk[ "envmap_fragment" ],
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'particle_basic': {
-
-		uniforms:  THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "particle" ],
-			THREE.UniformsLib[ "shadowmap" ]
-
-		] ),
-
-		vertexShader: [
-
-			"uniform float size;",
-			"uniform float scale;",
-
-			THREE.ShaderChunk[ "color_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "color_vertex" ],
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-				"#ifdef USE_SIZEATTENUATION",
-					"gl_PointSize = size * ( scale / length( mvPosition.xyz ) );",
-				"#else",
-					"gl_PointSize = size;",
-				"#endif",
-
-				"gl_Position = projectionMatrix * mvPosition;",
-
-				THREE.ShaderChunk[ "worldpos_vertex" ],
-				THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec3 psColor;",
-			"uniform float opacity;",
-
-			THREE.ShaderChunk[ "color_pars_fragment" ],
-			THREE.ShaderChunk[ "map_particle_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( psColor, opacity );",
-
-				THREE.ShaderChunk[ "map_particle_fragment" ],
-				THREE.ShaderChunk[ "alphatest_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'dashed': {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "common" ],
-			THREE.UniformsLib[ "fog" ],
-
-			{
-				"scale":     { type: "f", value: 1 },
-				"dashSize":  { type: "f", value: 1 },
-				"totalSize": { type: "f", value: 2 }
-			}
-
-		] ),
-
-		vertexShader: [
-
-			"uniform float scale;",
-			"attribute float lineDistance;",
-
-			"varying float vLineDistance;",
-
-			THREE.ShaderChunk[ "color_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "color_vertex" ],
-
-				"vLineDistance = scale * lineDistance;",
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-				"gl_Position = projectionMatrix * mvPosition;",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec3 diffuse;",
-			"uniform float opacity;",
-
-			"uniform float dashSize;",
-			"uniform float totalSize;",
-
-			"varying float vLineDistance;",
-
-			THREE.ShaderChunk[ "color_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-
-			"void main() {",
-
-				"if ( mod( vLineDistance, totalSize ) > dashSize ) {",
-
-					"discard;",
-
-				"}",
-
-				"gl_FragColor = vec4( diffuse, opacity );",
-
-				THREE.ShaderChunk[ "color_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'depth': {
-
-		uniforms: {
-
-			"mNear": { type: "f", value: 1.0 },
-			"mFar" : { type: "f", value: 2000.0 },
-			"opacity" : { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"void main() {",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float mNear;",
-			"uniform float mFar;",
-			"uniform float opacity;",
-
-			"void main() {",
-
-				"float depth = gl_FragCoord.z / gl_FragCoord.w;",
-				"float color = 1.0 - smoothstep( mNear, mFar, depth );",
-				"gl_FragColor = vec4( vec3( color ), opacity );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	'normal': {
-
-		uniforms: {
-
-			"opacity" : { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec3 vNormal;",
-
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-
-			"void main() {",
-
-				"vNormal = normalize( normalMatrix * normal );",
-
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "default_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-			"varying vec3 vNormal;",
-
-			"void main() {",
-
-				"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Normal map shader
-	//		- Blinn-Phong
-	//		- normal + diffuse + specular + AO + displacement + reflection + shadow maps
-	//		- point and directional lights (use with "lights: true" material option)
-	 ------------------------------------------------------------------------- */
-
-	'normalmap' : {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-			THREE.UniformsLib[ "shadowmap" ],
-
-			{
-
-			"enableAO"		  : { type: "i", value: 0 },
-			"enableDiffuse"	  : { type: "i", value: 0 },
-			"enableSpecular"  : { type: "i", value: 0 },
-			"enableReflection": { type: "i", value: 0 },
-			"enableDisplacement": { type: "i", value: 0 },
-
-			"tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture
-			"tDiffuse"	   : { type: "t", value: null },
-			"tCube"		   : { type: "t", value: null },
-			"tNormal"	   : { type: "t", value: null },
-			"tSpecular"	   : { type: "t", value: null },
-			"tAO"		   : { type: "t", value: null },
-
-			"uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) },
-
-			"uDisplacementBias": { type: "f", value: 0.0 },
-			"uDisplacementScale": { type: "f", value: 1.0 },
-
-			"uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) },
-			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) },
-			"uShininess": { type: "f", value: 30 },
-			"uOpacity": { type: "f", value: 1 },
-
-			"useRefract": { type: "i", value: 0 },
-			"uRefractionRatio": { type: "f", value: 0.98 },
-			"uReflectivity": { type: "f", value: 0.5 },
-
-			"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
-			"uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
-
-			"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
-
-			}
-
-		] ),
-
-		fragmentShader: [
-
-			"uniform vec3 uAmbientColor;",
-			"uniform vec3 uDiffuseColor;",
-			"uniform vec3 uSpecularColor;",
-			"uniform float uShininess;",
-			"uniform float uOpacity;",
-
-			"uniform bool enableDiffuse;",
-			"uniform bool enableSpecular;",
-			"uniform bool enableAO;",
-			"uniform bool enableReflection;",
-
-			"uniform sampler2D tDiffuse;",
-			"uniform sampler2D tNormal;",
-			"uniform sampler2D tSpecular;",
-			"uniform sampler2D tAO;",
-
-			"uniform samplerCube tCube;",
-
-			"uniform vec2 uNormalScale;",
-
-			"uniform bool useRefract;",
-			"uniform float uRefractionRatio;",
-			"uniform float uReflectivity;",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"uniform vec3 ambientLightColor;",
-
-			"#if MAX_DIR_LIGHTS > 0",
-
-				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-			"#endif",
-
-			"#if MAX_HEMI_LIGHTS > 0",
-
-				"uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
-				"uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
-				"uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
-
-			"#endif",
-
-			"#if MAX_POINT_LIGHTS > 0",
-
-				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-			"#endif",
-
-			"#if MAX_SPOT_LIGHTS > 0",
-
-				"uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
-				"uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-				"uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
-				"uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
-				"uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
-				"uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-
-			"#endif",
-
-			"#ifdef WRAP_AROUND",
-
-				"uniform vec3 wrapRGB;",
-
-			"#endif",
-
-			"varying vec3 vWorldPosition;",
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
-
-				"vec3 specularTex = vec3( 1.0 );",
-
-				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
-				"normalTex.xy *= uNormalScale;",
-				"normalTex = normalize( normalTex );",
-
-				"if( enableDiffuse ) {",
-
-					"#ifdef GAMMA_INPUT",
-
-						"vec4 texelColor = texture2D( tDiffuse, vUv );",
-						"texelColor.xyz *= texelColor.xyz;",
-
-						"gl_FragColor = gl_FragColor * texelColor;",
-
-					"#else",
-
-						"gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
-
-					"#endif",
-
-				"}",
-
-				"if( enableAO ) {",
-
-					"#ifdef GAMMA_INPUT",
-
-						"vec4 aoColor = texture2D( tAO, vUv );",
-						"aoColor.xyz *= aoColor.xyz;",
-
-						"gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
-
-					"#else",
-
-						"gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
-
-					"#endif",
-
-				"}",
-
-				"if( enableSpecular )",
-					"specularTex = texture2D( tSpecular, vUv ).xyz;",
-
-				"mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
-				"vec3 finalNormal = tsb * normalTex;",
-
-				"#ifdef FLIP_SIDED",
-
-					"finalNormal = -finalNormal;",
-
-				"#endif",
-
-				"vec3 normal = normalize( finalNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
-
-				// point lights
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"vec3 pointDiffuse = vec3( 0.0 );",
-					"vec3 pointSpecular = vec3( 0.0 );",
-
-					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-						"vec3 pointVector = lPosition.xyz + vViewPosition.xyz;",
-
-						"float pointDistance = 1.0;",
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-						"pointVector = normalize( pointVector );",
-
-						// diffuse
-
-						"#ifdef WRAP_AROUND",
-
-							"float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
-							"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",
-
-							"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
-
-						"#else",
-
-							"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
-
-						"#endif",
-
-						"pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",
-
-						// specular
-
-						"vec3 pointHalfVector = normalize( pointVector + viewPosition );",
-						"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
-						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",
-
-						"#ifdef PHYSICALLY_BASED_SHADING",
-
-							// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-							"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
-
-							"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );",
-							"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
-
-						"#else",
-
-							"pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;",
-
-						"#endif",
-
-					"}",
-
-				"#endif",
-
-				// spot lights
-
-				"#if MAX_SPOT_LIGHTS > 0",
-
-					"vec3 spotDiffuse = vec3( 0.0 );",
-					"vec3 spotSpecular = vec3( 0.0 );",
-
-					"for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-						"vec3 spotVector = lPosition.xyz + vViewPosition.xyz;",
-
-						"float spotDistance = 1.0;",
-						"if ( spotLightDistance[ i ] > 0.0 )",
-							"spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-						"spotVector = normalize( spotVector );",
-
-						"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
-
-						"if ( spotEffect > spotLightAngleCos[ i ] ) {",
-
-							"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
-
-							// diffuse
-
-							"#ifdef WRAP_AROUND",
-
-								"float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );",
-								"float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );",
-
-								"vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
-
-							"#else",
-
-								"float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );",
-
-							"#endif",
-
-							"spotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;",
-
-							// specular
-
-							"vec3 spotHalfVector = normalize( spotVector + viewPosition );",
-							"float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
-							"float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );",
-
-							"#ifdef PHYSICALLY_BASED_SHADING",
-
-								// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-								"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
-
-								"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );",
-								"spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",
-
-							"#else",
-
-								"spotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;",
-
-							"#endif",
-
-						"}",
-
-					"}",
-
-				"#endif",
-
-				// directional lights
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"vec3 dirDiffuse = vec3( 0.0 );",
-					"vec3 dirSpecular = vec3( 0.0 );",
-
-					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
-
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-						"vec3 dirVector = normalize( lDirection.xyz );",
-
-						// diffuse
-
-						"#ifdef WRAP_AROUND",
-
-							"float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
-							"float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
-
-							"vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",
-
-						"#else",
-
-							"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
-
-						"#endif",
-
-						"dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",
-
-						// specular
-
-						"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
-						"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
-						"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",
-
-						"#ifdef PHYSICALLY_BASED_SHADING",
-
-							// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-							"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
-
-							"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
-							"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
-
-						"#else",
-
-							"dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;",
-
-						"#endif",
-
-					"}",
-
-				"#endif",
-
-				// hemisphere lights
-
-				"#if MAX_HEMI_LIGHTS > 0",
-
-					"vec3 hemiDiffuse  = vec3( 0.0 );",
-					"vec3 hemiSpecular = vec3( 0.0 );" ,
-
-					"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
-
-						"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-						"vec3 lVector = normalize( lDirection.xyz );",
-
-						// diffuse
-
-						"float dotProduct = dot( normal, lVector );",
-						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
-
-						"vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
-
-						"hemiDiffuse += uDiffuseColor * hemiColor;",
-
-						// specular (sky light)
-
-
-						"vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
-						"float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
-						"float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );",
-
-						// specular (ground light)
-
-						"vec3 lVectorGround = -lVector;",
-
-						"vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
-						"float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
-						"float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );",
-
-						"#ifdef PHYSICALLY_BASED_SHADING",
-
-							"float dotProductGround = dot( normal, lVectorGround );",
-
-							// 2.0 => 2.0001 is hack to work around ANGLE bug
-
-							"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
-
-							"vec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
-							"vec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
-							"hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
-
-						"#else",
-
-							"hemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",
-
-						"#endif",
-
-					"}",
-
-				"#endif",
-
-				// all lights contribution summation
-
-				"vec3 totalDiffuse = vec3( 0.0 );",
-				"vec3 totalSpecular = vec3( 0.0 );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"totalDiffuse += dirDiffuse;",
-					"totalSpecular += dirSpecular;",
-
-				"#endif",
-
-				"#if MAX_HEMI_LIGHTS > 0",
-
-					"totalDiffuse += hemiDiffuse;",
-					"totalSpecular += hemiSpecular;",
-
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"totalDiffuse += pointDiffuse;",
-					"totalSpecular += pointSpecular;",
-
-				"#endif",
-
-				"#if MAX_SPOT_LIGHTS > 0",
-
-					"totalDiffuse += spotDiffuse;",
-					"totalSpecular += spotSpecular;",
-
-				"#endif",
-
-				"#ifdef METAL",
-
-					"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );",
-
-				"#else",
-
-					"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;",
-
-				"#endif",
-
-				"if ( enableReflection ) {",
-
-					"vec3 vReflect;",
-					"vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
-
-					"if ( useRefract ) {",
-
-						"vReflect = refract( cameraToVertex, normal, uRefractionRatio );",
-
-					"} else {",
-
-						"vReflect = reflect( cameraToVertex, normal );",
-
-					"}",
-
-					"vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
-
-					"#ifdef GAMMA_INPUT",
-
-						"cubeColor.xyz *= cubeColor.xyz;",
-
-					"#endif",
-
-					"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );",
-
-				"}",
-
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n"),
-
-		vertexShader: [
-
-			"attribute vec4 tangent;",
-
-			"uniform vec2 uOffset;",
-			"uniform vec2 uRepeat;",
-
-			"uniform bool enableDisplacement;",
-
-			"#ifdef VERTEX_TEXTURES",
-
-				"uniform sampler2D tDisplacement;",
-				"uniform float uDisplacementScale;",
-				"uniform float uDisplacementBias;",
-
-			"#endif",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"varying vec3 vWorldPosition;",
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-
-				// normal, tangent and binormal vectors
-
-				"#ifdef USE_SKINNING",
-
-					"vNormal = normalize( normalMatrix * skinnedNormal.xyz );",
-
-					"vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );",
-					"vTangent = normalize( normalMatrix * skinnedTangent.xyz );",
-
-				"#else",
-
-					"vNormal = normalize( normalMatrix * normal );",
-					"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"#endif",
-
-				"vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );",
-
-				"vUv = uv * uRepeat + uOffset;",
-
-				// displacement mapping
-
-				"vec3 displacedPosition;",
-
-				"#ifdef VERTEX_TEXTURES",
-
-					"if ( enableDisplacement ) {",
-
-						"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
-						"float df = uDisplacementScale * dv.x + uDisplacementBias;",
-						"displacedPosition = position + normalize( normal ) * df;",
-
-					"} else {",
-
-						"#ifdef USE_SKINNING",
-
-							"vec4 skinVertex = vec4( position, 1.0 );",
-
-							"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
-							"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
-
-							"displacedPosition  = skinned.xyz;",
-
-						"#else",
-
-							"displacedPosition = position;",
-
-						"#endif",
-
-					"}",
-
-				"#else",
-
-					"#ifdef USE_SKINNING",
-
-						"vec4 skinVertex = vec4( position, 1.0 );",
-
-						"vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
-						"skinned 	  += boneMatY * skinVertex * skinWeight.y;",
-
-						"displacedPosition  = skinned.xyz;",
-
-					"#else",
-
-						"displacedPosition = position;",
-
-					"#endif",
-
-				"#endif",
-
-				//
-
-				"vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );",
-				"vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );",
-
-				"gl_Position = projectionMatrix * mvPosition;",
-
-				//
-
-				"vWorldPosition = worldPosition.xyz;",
-				"vViewPosition = -mvPosition.xyz;",
-
-				// shadows
-
-				"#ifdef USE_SHADOWMAP",
-
-					"for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
-
-						"vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
-
-					"}",
-
-				"#endif",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Cube map shader
-	 ------------------------------------------------------------------------- */
-
-	'cube': {
-
-		uniforms: { "tCube": { type: "t", value: null },
-					"tFlip": { type: "f", value: -1 } },
-
-		vertexShader: [
-
-			"varying vec3 vWorldPosition;",
-
-			"void main() {",
-
-				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
-				"vWorldPosition = worldPosition.xyz;",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform samplerCube tCube;",
-			"uniform float tFlip;",
-
-			"varying vec3 vWorldPosition;",
-
-			"void main() {",
-
-				"gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	// Depth encoding into RGBA texture
-	// 	based on SpiderGL shadow map example
-	// 		http://spidergl.org/example.php?id=6
-	// 	originally from
-	//		http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD
-	// 	see also here:
-	//		http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/
-
-	'depthRGBA': {
-
-		uniforms: {},
-
-		vertexShader: [
-
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-
-			"void main() {",
-
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "skinning_vertex" ],
-				THREE.ShaderChunk[ "default_vertex" ],
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"vec4 pack_depth( const in float depth ) {",
-
-				"const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );",
-				"const vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );",
-				"vec4 res = fract( depth * bit_shift );",
-				"res -= res.xxyz * bit_mask;",
-				"return res;",
-
-			"}",
-
-			"void main() {",
-
-				"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );",
-
-				//"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );",
-				//"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );",
-				//"gl_FragData[ 0 ] = pack_depth( z );",
-				//"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );",
-
-			"}"
-
-		].join("\n")
-
-	}
-
-};
-/**
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author szimek / https://github.com/szimek/
- */
-
-THREE.WebGLRenderer = function ( parameters ) {
-
-	console.log( 'THREE.WebGLRenderer', THREE.REVISION );
-
-	parameters = parameters || {};
-
-	var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
-
-	_precision = parameters.precision !== undefined ? parameters.precision : 'highp',
-
-	_alpha = parameters.alpha !== undefined ? parameters.alpha : true,
-	_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
-	_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
-	_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
-	_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
-
-	_clearColor = new THREE.Color( 0x000000 ),
-	_clearAlpha = 0;
-
-	if ( parameters.clearColor !== undefined ) {
-
-		console.warn( 'DEPRECATED: clearColor in WebGLRenderer constructor parameters is being removed. Use .setClearColor() instead.' );
-		_clearColor.setHex( parameters.clearColor );
-
-	}
-
-	if ( parameters.clearAlpha !== undefined ) {
-
-		console.warn( 'DEPRECATED: clearAlpha in WebGLRenderer constructor parameters is being removed. Use .setClearColor() instead.' );
-		_clearAlpha = parameters.clearAlpha;
-
-	}
-
-	// public properties
-
-	this.domElement = _canvas;
-	this.context = null;
-	this.devicePixelRatio = parameters.devicePixelRatio !== undefined
-				? parameters.devicePixelRatio
-				: window.devicePixelRatio !== undefined
-					? window.devicePixelRatio
-					: 1;
-
-	// clearing
-
-	this.autoClear = true;
-	this.autoClearColor = true;
-	this.autoClearDepth = true;
-	this.autoClearStencil = true;
-
-	// scene graph
-
-	this.sortObjects = true;
-	this.autoUpdateObjects = true;
-
-	// physically based shading
-
-	this.gammaInput = false;
-	this.gammaOutput = false;
-	this.physicallyBasedShading = false;
-
-	// shadow map
-
-	this.shadowMapEnabled = false;
-	this.shadowMapAutoUpdate = true;
-	this.shadowMapType = THREE.PCFShadowMap;
-	this.shadowMapCullFace = THREE.CullFaceFront;
-	this.shadowMapDebug = false;
-	this.shadowMapCascade = false;
-
-	// morphs
-
-	this.maxMorphTargets = 8;
-	this.maxMorphNormals = 4;
-
-	// flags
-
-	this.autoScaleCubemaps = true;
-
-	// custom render plugins
-
-	this.renderPluginsPre = [];
-	this.renderPluginsPost = [];
-
-	// info
-
-	this.info = {
-
-		memory: {
-
-			programs: 0,
-			geometries: 0,
-			textures: 0
-
-		},
-
-		render: {
-
-			calls: 0,
-			vertices: 0,
-			faces: 0,
-			points: 0
-
-		}
-
-	};
-
-	// internal properties
-
-	var _this = this,
-
-	_programs = [],
-	_programs_counter = 0,
-
-	// internal state cache
-
-	_currentProgram = null,
-	_currentFramebuffer = null,
-	_currentMaterialId = -1,
-	_currentGeometryGroupHash = null,
-	_currentCamera = null,
-	_geometryGroupCounter = 0,
-
-	_usedTextureUnits = 0,
-
-	// GL state cache
-
-	_oldDoubleSided = -1,
-	_oldFlipSided = -1,
-
-	_oldBlending = -1,
-
-	_oldBlendEquation = -1,
-	_oldBlendSrc = -1,
-	_oldBlendDst = -1,
-
-	_oldDepthTest = -1,
-	_oldDepthWrite = -1,
-
-	_oldPolygonOffset = null,
-	_oldPolygonOffsetFactor = null,
-	_oldPolygonOffsetUnits = null,
-
-	_oldLineWidth = null,
-
-	_viewportX = 0,
-	_viewportY = 0,
-	_viewportWidth = 0,
-	_viewportHeight = 0,
-	_currentWidth = 0,
-	_currentHeight = 0,
-
-	_enabledAttributes = {},
-
-	// frustum
-
-	_frustum = new THREE.Frustum(),
-
-	 // camera matrices cache
-
-	_projScreenMatrix = new THREE.Matrix4(),
-	_projScreenMatrixPS = new THREE.Matrix4(),
-
-	_vector3 = new THREE.Vector3(),
-
-	// light arrays cache
-
-	_direction = new THREE.Vector3(),
-
-	_lightsNeedUpdate = true,
-
-	_lights = {
-
-		ambient: [ 0, 0, 0 ],
-		directional: { length: 0, colors: new Array(), positions: new Array() },
-		point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() },
-		spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() },
-		hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }
-
-	};
-
-	// initialize
-
-	var _gl;
-
-	var _glExtensionTextureFloat;
-	var _glExtensionStandardDerivatives;
-	var _glExtensionTextureFilterAnisotropic;
-	var _glExtensionCompressedTextureS3TC;
-
-	initGL();
-
-	setDefaultGLState();
-
-	this.context = _gl;
-
-	// GPU capabilities
-
-	var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
-	var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
-	var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
-	var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
-
-	var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
-
-	var _supportsVertexTextures = ( _maxVertexTextures > 0 );
-	var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
-
-	var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
-
-	//
-
-	var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
-	var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
-	var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
-
-	var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
-	var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
-	var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
-
-	var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
-	var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
-	var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
-
-	var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
-	var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
-	var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
-
-	// clamp precision to maximum available
-
-	var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
-	var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
-
-	if ( _precision === "highp" && ! highpAvailable ) {
-
-		if ( mediumpAvailable ) {
-
-			_precision = "mediump";
-			console.warn( "WebGLRenderer: highp not supported, using mediump" );
-
-		} else {
-
-			_precision = "lowp";
-			console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" );
-
-		}
-
-	}
-
-	if ( _precision === "mediump" && ! mediumpAvailable ) {
-
-		_precision = "lowp";
-		console.warn( "WebGLRenderer: mediump not supported, using lowp" );
-
-	}
-
-	// API
-
-	this.getContext = function () {
-
-		return _gl;
-
-	};
-
-	this.supportsVertexTextures = function () {
-
-		return _supportsVertexTextures;
-
-	};
-
-	this.supportsFloatTextures = function () {
-
-		return _glExtensionTextureFloat;
-
-	};
-
-	this.supportsStandardDerivatives = function () {
-
-		return _glExtensionStandardDerivatives;
-
-	};
-
-	this.supportsCompressedTextureS3TC = function () {
-
-		return _glExtensionCompressedTextureS3TC;
-
-	};
-
-	this.getMaxAnisotropy  = function () {
-
-		return _maxAnisotropy;
-
-	};
-
-	this.getPrecision = function () {
-
-		return _precision;
-
-	};
-
-	this.setSize = function ( width, height, updateStyle ) {
-
-		_canvas.width = width * this.devicePixelRatio;
-		_canvas.height = height * this.devicePixelRatio;
-
-		if ( this.devicePixelRatio !== 1 && updateStyle !== false ) {
-
-			_canvas.style.width = width + 'px';
-			_canvas.style.height = height + 'px';
-
-		}
-
-		this.setViewport( 0, 0, _canvas.width, _canvas.height );
-
-	};
-
-	this.setViewport = function ( x, y, width, height ) {
-
-		_viewportX = x !== undefined ? x : 0;
-		_viewportY = y !== undefined ? y : 0;
-
-		_viewportWidth = width !== undefined ? width : _canvas.width;
-		_viewportHeight = height !== undefined ? height : _canvas.height;
-
-		_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
-
-	};
-
-	this.setScissor = function ( x, y, width, height ) {
-
-		_gl.scissor( x, y, width, height );
-
-	};
-
-	this.enableScissorTest = function ( enable ) {
-
-		enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
-
-	};
-
-	// Clearing
-
-	this.setClearColor = function ( color, alpha ) {
-
-		_clearColor.set( color );
-		_clearAlpha = alpha !== undefined ? alpha : 1;
-
-		_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
-
-	};
-
-	this.setClearColorHex = function ( hex, alpha ) {
-
-		console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
-		this.setClearColor( hex, alpha );
-
-	};
-
-	this.getClearColor = function () {
-
-		return _clearColor;
-
-	};
-
-	this.getClearAlpha = function () {
-
-		return _clearAlpha;
-
-	};
-
-	this.clear = function ( color, depth, stencil ) {
-
-		var bits = 0;
-
-		if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
-		if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
-		if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
-
-		_gl.clear( bits );
-
-	};
-
-	this.clearTarget = function ( renderTarget, color, depth, stencil ) {
-
-		this.setRenderTarget( renderTarget );
-		this.clear( color, depth, stencil );
-
-	};
-
-	// Plugins
-
-	this.addPostPlugin = function ( plugin ) {
-
-		plugin.init( this );
-		this.renderPluginsPost.push( plugin );
-
-	};
-
-	this.addPrePlugin = function ( plugin ) {
-
-		plugin.init( this );
-		this.renderPluginsPre.push( plugin );
-
-	};
-
-	// Rendering
-
-	this.updateShadowMap = function ( scene, camera ) {
-
-		_currentProgram = null;
-		_oldBlending = -1;
-		_oldDepthTest = -1;
-		_oldDepthWrite = -1;
-		_currentGeometryGroupHash = -1;
-		_currentMaterialId = -1;
-		_lightsNeedUpdate = true;
-		_oldDoubleSided = -1;
-		_oldFlipSided = -1;
-
-		this.shadowMapPlugin.update( scene, camera );
-
-	};
-
-	// Internal functions
-
-	// Buffer allocation
-
-	function createParticleBuffers ( geometry ) {
-
-		geometry.__webglVertexBuffer = _gl.createBuffer();
-		geometry.__webglColorBuffer = _gl.createBuffer();
-
-		_this.info.memory.geometries ++;
-
-	};
-
-	function createLineBuffers ( geometry ) {
-
-		geometry.__webglVertexBuffer = _gl.createBuffer();
-		geometry.__webglColorBuffer = _gl.createBuffer();
-		geometry.__webglLineDistanceBuffer = _gl.createBuffer();
-
-		_this.info.memory.geometries ++;
-
-	};
-
-	function createRibbonBuffers ( geometry ) {
-
-		geometry.__webglVertexBuffer = _gl.createBuffer();
-		geometry.__webglColorBuffer = _gl.createBuffer();
-		geometry.__webglNormalBuffer = _gl.createBuffer();
-
-		_this.info.memory.geometries ++;
-
-	};
-
-	function createMeshBuffers ( geometryGroup ) {
-
-		geometryGroup.__webglVertexBuffer = _gl.createBuffer();
-		geometryGroup.__webglNormalBuffer = _gl.createBuffer();
-		geometryGroup.__webglTangentBuffer = _gl.createBuffer();
-		geometryGroup.__webglColorBuffer = _gl.createBuffer();
-		geometryGroup.__webglUVBuffer = _gl.createBuffer();
-		geometryGroup.__webglUV2Buffer = _gl.createBuffer();
-
-		geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
-		geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
-
-		geometryGroup.__webglFaceBuffer = _gl.createBuffer();
-		geometryGroup.__webglLineBuffer = _gl.createBuffer();
-
-		var m, ml;
-
-		if ( geometryGroup.numMorphTargets ) {
-
-			geometryGroup.__webglMorphTargetsBuffers = [];
-
-			for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
-
-				geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );
-
-			}
-
-		}
-
-		if ( geometryGroup.numMorphNormals ) {
-
-			geometryGroup.__webglMorphNormalsBuffers = [];
-
-			for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
-
-				geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );
-
-			}
-
-		}
-
-		_this.info.memory.geometries ++;
-
-	};
-
-	// Events
-
-	var onGeometryDispose = function ( event ) {
-
-		var geometry = event.target;
-
-		geometry.removeEventListener( 'dispose', onGeometryDispose );
-
-		deallocateGeometry( geometry );
-
-		_this.info.memory.geometries --;
-
-	};
-
-	var onTextureDispose = function ( event ) {
-
-		var texture = event.target;
-
-		texture.removeEventListener( 'dispose', onTextureDispose );
-
-		deallocateTexture( texture );
-
-		_this.info.memory.textures --;
-
-
-	};
-
-	var onRenderTargetDispose = function ( event ) {
-
-		var renderTarget = event.target;
-
-		renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
-
-		deallocateRenderTarget( renderTarget );
-
-		_this.info.memory.textures --;
-
-	};
-
-	var onMaterialDispose = function ( event ) {
-
-		var material = event.target;
-
-		material.removeEventListener( 'dispose', onMaterialDispose );
-
-		deallocateMaterial( material );
-
-	};
-
-	// Buffer deallocation
-
-	var deallocateGeometry = function ( geometry ) {
-
-		geometry.__webglInit = undefined;
-
-		if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer );
-		if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer );
-		if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer );
-		if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer );
-		if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer );
-		if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer );
-
-		if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer );
-		if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer );
-
-		if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer );
-		if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer );
-
-		if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer );
-
-		// geometry groups
-
-		if ( geometry.geometryGroups !== undefined ) {
-
-			for ( var g in geometry.geometryGroups ) {
-
-				var geometryGroup = geometry.geometryGroups[ g ];
-
-				if ( geometryGroup.numMorphTargets !== undefined ) {
-
-					for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
-
-						_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
-
-					}
-
-				}
-
-				if ( geometryGroup.numMorphNormals !== undefined ) {
-
-					for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
-
-						_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
-
-					}
-
-				}
-
-				deleteCustomAttributesBuffers( geometryGroup );
-
-			}
-
-		}
-
-		deleteCustomAttributesBuffers( geometry );
-
-	};
-
-	var deallocateTexture = function ( texture ) {
-
-		if ( texture.image && texture.image.__webglTextureCube ) {
-
-			// cube texture
-
-			_gl.deleteTexture( texture.image.__webglTextureCube );
-
-		} else {
-
-			// 2D texture
-
-			if ( ! texture.__webglInit ) return;
-
-			texture.__webglInit = false;
-			_gl.deleteTexture( texture.__webglTexture );
-
-		}
-
-	};
-
-	var deallocateRenderTarget = function ( renderTarget ) {
-
-		if ( !renderTarget || ! renderTarget.__webglTexture ) return;
-
-		_gl.deleteTexture( renderTarget.__webglTexture );
-
-		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
-
-			for ( var i = 0; i < 6; i ++ ) {
-
-				_gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
-				_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
-
-			}
-
-		} else {
-
-			_gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
-			_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
-
-		}
-
-	};
-
-	var deallocateMaterial = function ( material ) {
-
-		var program = material.program;
-
-		if ( program === undefined ) return;
-
-		material.program = undefined;
-
-		// only deallocate GL program if this was the last use of shared program
-		// assumed there is only single copy of any program in the _programs list
-		// (that's how it's constructed)
-
-		var i, il, programInfo;
-		var deleteProgram = false;
-
-		for ( i = 0, il = _programs.length; i < il; i ++ ) {
-
-			programInfo = _programs[ i ];
-
-			if ( programInfo.program === program ) {
-
-				programInfo.usedTimes --;
-
-				if ( programInfo.usedTimes === 0 ) {
-
-					deleteProgram = true;
-
-				}
-
-				break;
-
-			}
-
-		}
-
-		if ( deleteProgram === true ) {
-
-			// avoid using array.splice, this is costlier than creating new array from scratch
-
-			var newPrograms = [];
-
-			for ( i = 0, il = _programs.length; i < il; i ++ ) {
-
-				programInfo = _programs[ i ];
-
-				if ( programInfo.program !== program ) {
-
-					newPrograms.push( programInfo );
-
-				}
-
-			}
-
-			_programs = newPrograms;
-
-			_gl.deleteProgram( program );
-
-			_this.info.memory.programs --;
-
-		}
-
-	};
-
-	//
-
-	/*
-	function deleteParticleBuffers ( geometry ) {
-
-		_gl.deleteBuffer( geometry.__webglVertexBuffer );
-		_gl.deleteBuffer( geometry.__webglColorBuffer );
-
-		deleteCustomAttributesBuffers( geometry );
-
-		_this.info.memory.geometries --;
-
-	};
-
-	function deleteLineBuffers ( geometry ) {
-
-		_gl.deleteBuffer( geometry.__webglVertexBuffer );
-		_gl.deleteBuffer( geometry.__webglColorBuffer );
-		_gl.deleteBuffer( geometry.__webglLineDistanceBuffer );
-
-		deleteCustomAttributesBuffers( geometry );
-
-		_this.info.memory.geometries --;
-
-	};
-
-	function deleteRibbonBuffers ( geometry ) {
-
-		_gl.deleteBuffer( geometry.__webglVertexBuffer );
-		_gl.deleteBuffer( geometry.__webglColorBuffer );
-		_gl.deleteBuffer( geometry.__webglNormalBuffer );
-
-		deleteCustomAttributesBuffers( geometry );
-
-		_this.info.memory.geometries --;
-
-	};
-
-	function deleteMeshBuffers ( geometryGroup ) {
-
-		_gl.deleteBuffer( geometryGroup.__webglVertexBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglNormalBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglTangentBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglColorBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglUVBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglUV2Buffer );
-
-		_gl.deleteBuffer( geometryGroup.__webglSkinIndicesBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglSkinWeightsBuffer );
-
-		_gl.deleteBuffer( geometryGroup.__webglFaceBuffer );
-		_gl.deleteBuffer( geometryGroup.__webglLineBuffer );
-
-		var m, ml;
-
-		if ( geometryGroup.numMorphTargets ) {
-
-			for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
-
-				_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
-
-			}
-
-		}
-
-		if ( geometryGroup.numMorphNormals ) {
-
-			for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
-
-				_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
-
-			}
-
-		}
-
-		deleteCustomAttributesBuffers( geometryGroup );
-
-		_this.info.memory.geometries --;
-
-	};
-	*/
-
-	function deleteCustomAttributesBuffers( geometry ) {
-
-		if ( geometry.__webglCustomAttributesList ) {
-
-			for ( var id in geometry.__webglCustomAttributesList ) {
-
-				_gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer );
-
-			}
-
-		}
-
-	};
-
-	// Buffer initialization
-
-	function initCustomAttributes ( geometry, object ) {
-
-		var nvertices = geometry.vertices.length;
-
-		var material = object.material;
-
-		if ( material.attributes ) {
-
-			if ( geometry.__webglCustomAttributesList === undefined ) {
-
-				geometry.__webglCustomAttributesList = [];
-
-			}
-
-			for ( var a in material.attributes ) {
-
-				var attribute = material.attributes[ a ];
-
-				if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
-
-					attribute.__webglInitialized = true;
-
-					var size = 1;		// "f" and "i"
-
-					if ( attribute.type === "v2" ) size = 2;
-					else if ( attribute.type === "v3" ) size = 3;
-					else if ( attribute.type === "v4" ) size = 4;
-					else if ( attribute.type === "c"  ) size = 3;
-
-					attribute.size = size;
-
-					attribute.array = new Float32Array( nvertices * size );
-
-					attribute.buffer = _gl.createBuffer();
-					attribute.buffer.belongsToAttribute = a;
-
-					attribute.needsUpdate = true;
-
-				}
-
-				geometry.__webglCustomAttributesList.push( attribute );
-
-			}
-
-		}
-
-	};
-
-	function initParticleBuffers ( geometry, object ) {
-
-		var nvertices = geometry.vertices.length;
-
-		geometry.__vertexArray = new Float32Array( nvertices * 3 );
-		geometry.__colorArray = new Float32Array( nvertices * 3 );
-
-		geometry.__sortArray = [];
-
-		geometry.__webglParticleCount = nvertices;
-
-		initCustomAttributes ( geometry, object );
-
-	};
-
-	function initLineBuffers ( geometry, object ) {
-
-		var nvertices = geometry.vertices.length;
-
-		geometry.__vertexArray = new Float32Array( nvertices * 3 );
-		geometry.__colorArray = new Float32Array( nvertices * 3 );
-		geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
-
-		geometry.__webglLineCount = nvertices;
-
-		initCustomAttributes ( geometry, object );
-
-	};
-
-	function initRibbonBuffers ( geometry, object ) {
-
-		var nvertices = geometry.vertices.length;
-
-		geometry.__vertexArray = new Float32Array( nvertices * 3 );
-		geometry.__colorArray = new Float32Array( nvertices * 3 );
-		geometry.__normalArray = new Float32Array( nvertices * 3 );
-
-		geometry.__webglVertexCount = nvertices;
-
-		initCustomAttributes ( geometry, object );
-
-	};
-
-	function initMeshBuffers ( geometryGroup, object ) {
-
-		var geometry = object.geometry,
-			faces3 = geometryGroup.faces3,
-			faces4 = geometryGroup.faces4,
-
-			nvertices = faces3.length * 3 + faces4.length * 4,
-			ntris     = faces3.length * 1 + faces4.length * 2,
-			nlines    = faces3.length * 3 + faces4.length * 4,
-
-			material = getBufferMaterial( object, geometryGroup ),
-
-			uvType = bufferGuessUVType( material ),
-			normalType = bufferGuessNormalType( material ),
-			vertexColorType = bufferGuessVertexColorType( material );
-
-		// console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );
-
-		geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
-
-		if ( normalType ) {
-
-			geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
-
-		}
-
-		if ( geometry.hasTangents ) {
-
-			geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
-
-		}
-
-		if ( vertexColorType ) {
-
-			geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
-
-		}
-
-		if ( uvType ) {
-
-			if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) {
-
-				geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
-
-			}
-
-			if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) {
-
-				geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
-
-			}
-
-		}
-
-		if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
-
-			geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
-			geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
-
-		}
-
-		geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
-		geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
-
-		var m, ml;
-
-		if ( geometryGroup.numMorphTargets ) {
-
-			geometryGroup.__morphTargetsArrays = [];
-
-			for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
-
-				geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
-
-			}
-
-		}
-
-		if ( geometryGroup.numMorphNormals ) {
-
-			geometryGroup.__morphNormalsArrays = [];
-
-			for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
-
-				geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );
-
-			}
-
-		}
-
-		geometryGroup.__webglFaceCount = ntris * 3;
-		geometryGroup.__webglLineCount = nlines * 2;
-
-
-		// custom attributes
-
-		if ( material.attributes ) {
-
-			if ( geometryGroup.__webglCustomAttributesList === undefined ) {
-
-				geometryGroup.__webglCustomAttributesList = [];
-
-			}
-
-			for ( var a in material.attributes ) {
-
-				// Do a shallow copy of the attribute object so different geometryGroup chunks use different
-				// attribute buffers which are correctly indexed in the setMeshBuffers function
-
-				var originalAttribute = material.attributes[ a ];
-
-				var attribute = {};
-
-				for ( var property in originalAttribute ) {
-
-					attribute[ property ] = originalAttribute[ property ];
-
-				}
-
-				if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
-
-					attribute.__webglInitialized = true;
-
-					var size = 1;		// "f" and "i"
-
-					if( attribute.type === "v2" ) size = 2;
-					else if( attribute.type === "v3" ) size = 3;
-					else if( attribute.type === "v4" ) size = 4;
-					else if( attribute.type === "c"  ) size = 3;
-
-					attribute.size = size;
-
-					attribute.array = new Float32Array( nvertices * size );
-
-					attribute.buffer = _gl.createBuffer();
-					attribute.buffer.belongsToAttribute = a;
-
-					originalAttribute.needsUpdate = true;
-					attribute.__original = originalAttribute;
-
-				}
-
-				geometryGroup.__webglCustomAttributesList.push( attribute );
-
-			}
-
-		}
-
-		geometryGroup.__inittedArrays = true;
-
-	};
-
-	function getBufferMaterial( object, geometryGroup ) {
-
-		return object.material instanceof THREE.MeshFaceMaterial
-			? object.material.materials[ geometryGroup.materialIndex ]
-			: object.material;
-
-	};
-
-	function materialNeedsSmoothNormals ( material ) {
-
-		return material && material.shading !== undefined && material.shading === THREE.SmoothShading;
-
-	};
-
-	function bufferGuessNormalType ( material ) {
-
-		// only MeshBasicMaterial and MeshDepthMaterial don't need normals
-
-		if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {
-
-			return false;
-
-		}
-
-		if ( materialNeedsSmoothNormals( material ) ) {
-
-			return THREE.SmoothShading;
-
-		} else {
-
-			return THREE.FlatShading;
-
-		}
-
-	};
-
-	function bufferGuessVertexColorType( material ) {
-
-		if ( material.vertexColors ) {
-
-			return material.vertexColors;
-
-		}
-
-		return false;
-
-	};
-
-	function bufferGuessUVType( material ) {
-
-		// material must use some texture to require uvs
-
-		if ( material.map ||
-		     material.lightMap ||
-		     material.bumpMap ||
-		     material.normalMap ||
-		     material.specularMap ||
-		     material instanceof THREE.ShaderMaterial ) {
-
-			return true;
-
-		}
-
-		return false;
-
-	};
-
-	//
-
-	function initDirectBuffers( geometry ) {
-
-		var a, attribute, type;
-
-		for ( a in geometry.attributes ) {
-
-			if ( a === "index" ) {
-
-				type = _gl.ELEMENT_ARRAY_BUFFER;
-
-			} else {
-
-				type = _gl.ARRAY_BUFFER;
-
-			}
-
-			attribute = geometry.attributes[ a ];
-
-			attribute.buffer = _gl.createBuffer();
-
-			_gl.bindBuffer( type, attribute.buffer );
-			_gl.bufferData( type, attribute.array, _gl.STATIC_DRAW );
-
-		}
-
-	};
-
-	// Buffer setting
-
-	function setParticleBuffers ( geometry, hint, object ) {
-
-		var v, c, vertex, offset, index, color,
-
-		vertices = geometry.vertices,
-		vl = vertices.length,
-
-		colors = geometry.colors,
-		cl = colors.length,
-
-		vertexArray = geometry.__vertexArray,
-		colorArray = geometry.__colorArray,
-
-		sortArray = geometry.__sortArray,
-
-		dirtyVertices = geometry.verticesNeedUpdate,
-		dirtyElements = geometry.elementsNeedUpdate,
-		dirtyColors = geometry.colorsNeedUpdate,
-
-		customAttributes = geometry.__webglCustomAttributesList,
-		i, il,
-		a, ca, cal, value,
-		customAttribute;
-
-		if ( object.sortParticles ) {
-
-			_projScreenMatrixPS.copy( _projScreenMatrix );
-			_projScreenMatrixPS.multiply( object.matrixWorld );
-
-			for ( v = 0; v < vl; v ++ ) {
-
-				vertex = vertices[ v ];
-
-				_vector3.copy( vertex );
-				_vector3.applyProjection( _projScreenMatrixPS );
-
-				sortArray[ v ] = [ _vector3.z, v ];
-
-			}
-
-			sortArray.sort( numericalSort );
-
-			for ( v = 0; v < vl; v ++ ) {
-
-				vertex = vertices[ sortArray[v][1] ];
-
-				offset = v * 3;
-
-				vertexArray[ offset ]     = vertex.x;
-				vertexArray[ offset + 1 ] = vertex.y;
-				vertexArray[ offset + 2 ] = vertex.z;
-
-			}
-
-			for ( c = 0; c < cl; c ++ ) {
-
-				offset = c * 3;
-
-				color = colors[ sortArray[c][1] ];
-
-				colorArray[ offset ]     = color.r;
-				colorArray[ offset + 1 ] = color.g;
-				colorArray[ offset + 2 ] = color.b;
-
-			}
-
-			if ( customAttributes ) {
-
-				for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-					customAttribute = customAttributes[ i ];
-
-					if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;
-
-					offset = 0;
-
-					cal = customAttribute.value.length;
-
-					if ( customAttribute.size === 1 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							index = sortArray[ ca ][ 1 ];
-
-							customAttribute.array[ ca ] = customAttribute.value[ index ];
-
-						}
-
-					} else if ( customAttribute.size === 2 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							index = sortArray[ ca ][ 1 ];
-
-							value = customAttribute.value[ index ];
-
-							customAttribute.array[ offset ] 	= value.x;
-							customAttribute.array[ offset + 1 ] = value.y;
-
-							offset += 2;
-
-						}
-
-					} else if ( customAttribute.size === 3 ) {
-
-						if ( customAttribute.type === "c" ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								index = sortArray[ ca ][ 1 ];
-
-								value = customAttribute.value[ index ];
-
-								customAttribute.array[ offset ]     = value.r;
-								customAttribute.array[ offset + 1 ] = value.g;
-								customAttribute.array[ offset + 2 ] = value.b;
-
-								offset += 3;
-
-							}
-
-						} else {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								index = sortArray[ ca ][ 1 ];
-
-								value = customAttribute.value[ index ];
-
-								customAttribute.array[ offset ] 	= value.x;
-								customAttribute.array[ offset + 1 ] = value.y;
-								customAttribute.array[ offset + 2 ] = value.z;
-
-								offset += 3;
-
-							}
-
-						}
-
-					} else if ( customAttribute.size === 4 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							index = sortArray[ ca ][ 1 ];
-
-							value = customAttribute.value[ index ];
-
-							customAttribute.array[ offset ]      = value.x;
-							customAttribute.array[ offset + 1  ] = value.y;
-							customAttribute.array[ offset + 2  ] = value.z;
-							customAttribute.array[ offset + 3  ] = value.w;
-
-							offset += 4;
-
-						}
-
-					}
-
-				}
-
-			}
-
-		} else {
-
-			if ( dirtyVertices ) {
-
-				for ( v = 0; v < vl; v ++ ) {
-
-					vertex = vertices[ v ];
-
-					offset = v * 3;
-
-					vertexArray[ offset ]     = vertex.x;
-					vertexArray[ offset + 1 ] = vertex.y;
-					vertexArray[ offset + 2 ] = vertex.z;
-
-				}
-
-			}
-
-			if ( dirtyColors ) {
-
-				for ( c = 0; c < cl; c ++ ) {
-
-					color = colors[ c ];
-
-					offset = c * 3;
-
-					colorArray[ offset ]     = color.r;
-					colorArray[ offset + 1 ] = color.g;
-					colorArray[ offset + 2 ] = color.b;
-
-				}
-
-			}
-
-			if ( customAttributes ) {
-
-				for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-					customAttribute = customAttributes[ i ];
-
-					if ( customAttribute.needsUpdate &&
-						 ( customAttribute.boundTo === undefined ||
-						   customAttribute.boundTo === "vertices") ) {
-
-						cal = customAttribute.value.length;
-
-						offset = 0;
-
-						if ( customAttribute.size === 1 ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								customAttribute.array[ ca ] = customAttribute.value[ ca ];
-
-							}
-
-						} else if ( customAttribute.size === 2 ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ] 	= value.x;
-								customAttribute.array[ offset + 1 ] = value.y;
-
-								offset += 2;
-
-							}
-
-						} else if ( customAttribute.size === 3 ) {
-
-							if ( customAttribute.type === "c" ) {
-
-								for ( ca = 0; ca < cal; ca ++ ) {
-
-									value = customAttribute.value[ ca ];
-
-									customAttribute.array[ offset ] 	= value.r;
-									customAttribute.array[ offset + 1 ] = value.g;
-									customAttribute.array[ offset + 2 ] = value.b;
-
-									offset += 3;
-
-								}
-
-							} else {
-
-								for ( ca = 0; ca < cal; ca ++ ) {
-
-									value = customAttribute.value[ ca ];
-
-									customAttribute.array[ offset ] 	= value.x;
-									customAttribute.array[ offset + 1 ] = value.y;
-									customAttribute.array[ offset + 2 ] = value.z;
-
-									offset += 3;
-
-								}
-
-							}
-
-						} else if ( customAttribute.size === 4 ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ]      = value.x;
-								customAttribute.array[ offset + 1  ] = value.y;
-								customAttribute.array[ offset + 2  ] = value.z;
-								customAttribute.array[ offset + 3  ] = value.w;
-
-								offset += 4;
-
-							}
-
-						}
-
-					}
-
-				}
-
-			}
-
-		}
-
-		if ( dirtyVertices || object.sortParticles ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
-		}
-
-		if ( dirtyColors || object.sortParticles ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
-		}
-
-		if ( customAttributes ) {
-
-			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-				customAttribute = customAttributes[ i ];
-
-				if ( customAttribute.needsUpdate || object.sortParticles ) {
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
-					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
-				}
-
-			}
-
-		}
-
-
-	};
-
-	function setLineBuffers ( geometry, hint ) {
-
-		var v, c, d, vertex, offset, color,
-
-		vertices = geometry.vertices,
-		colors = geometry.colors,
-		lineDistances = geometry.lineDistances,
-
-		vl = vertices.length,
-		cl = colors.length,
-		dl = lineDistances.length,
-
-		vertexArray = geometry.__vertexArray,
-		colorArray = geometry.__colorArray,
-		lineDistanceArray = geometry.__lineDistanceArray,
-
-		dirtyVertices = geometry.verticesNeedUpdate,
-		dirtyColors = geometry.colorsNeedUpdate,
-		dirtyLineDistances = geometry.lineDistancesNeedUpdate,
-
-		customAttributes = geometry.__webglCustomAttributesList,
-
-		i, il,
-		a, ca, cal, value,
-		customAttribute;
-
-		if ( dirtyVertices ) {
-
-			for ( v = 0; v < vl; v ++ ) {
-
-				vertex = vertices[ v ];
-
-				offset = v * 3;
-
-				vertexArray[ offset ]     = vertex.x;
-				vertexArray[ offset + 1 ] = vertex.y;
-				vertexArray[ offset + 2 ] = vertex.z;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
-		}
-
-		if ( dirtyColors ) {
-
-			for ( c = 0; c < cl; c ++ ) {
-
-				color = colors[ c ];
-
-				offset = c * 3;
-
-				colorArray[ offset ]     = color.r;
-				colorArray[ offset + 1 ] = color.g;
-				colorArray[ offset + 2 ] = color.b;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
-		}
-
-		if ( dirtyLineDistances ) {
-
-			for ( d = 0; d < dl; d ++ ) {
-
-				lineDistanceArray[ d ] = lineDistances[ d ];
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );
-
-		}
-
-		if ( customAttributes ) {
-
-			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-				customAttribute = customAttributes[ i ];
-
-				if ( customAttribute.needsUpdate &&
-					 ( customAttribute.boundTo === undefined ||
-					   customAttribute.boundTo === "vertices" ) ) {
-
-					offset = 0;
-
-					cal = customAttribute.value.length;
-
-					if ( customAttribute.size === 1 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							customAttribute.array[ ca ] = customAttribute.value[ ca ];
-
-						}
-
-					} else if ( customAttribute.size === 2 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							value = customAttribute.value[ ca ];
-
-							customAttribute.array[ offset ] 	= value.x;
-							customAttribute.array[ offset + 1 ] = value.y;
-
-							offset += 2;
-
-						}
-
-					} else if ( customAttribute.size === 3 ) {
-
-						if ( customAttribute.type === "c" ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ] 	= value.r;
-								customAttribute.array[ offset + 1 ] = value.g;
-								customAttribute.array[ offset + 2 ] = value.b;
-
-								offset += 3;
-
-							}
-
-						} else {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ] 	= value.x;
-								customAttribute.array[ offset + 1 ] = value.y;
-								customAttribute.array[ offset + 2 ] = value.z;
-
-								offset += 3;
-
-							}
-
-						}
-
-					} else if ( customAttribute.size === 4 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							value = customAttribute.value[ ca ];
-
-							customAttribute.array[ offset ] 	 = value.x;
-							customAttribute.array[ offset + 1  ] = value.y;
-							customAttribute.array[ offset + 2  ] = value.z;
-							customAttribute.array[ offset + 3  ] = value.w;
-
-							offset += 4;
-
-						}
-
-					}
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
-					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function setRibbonBuffers ( geometry, hint ) {
-
-		var v, c, n, vertex, offset, color, normal,
-
-		i, il, ca, cal, customAttribute, value,
-
-		vertices = geometry.vertices,
-		colors = geometry.colors,
-		normals = geometry.normals,
-
-		vl = vertices.length,
-		cl = colors.length,
-		nl = normals.length,
-
-		vertexArray = geometry.__vertexArray,
-		colorArray = geometry.__colorArray,
-		normalArray = geometry.__normalArray,
-
-		dirtyVertices = geometry.verticesNeedUpdate,
-		dirtyColors = geometry.colorsNeedUpdate,
-		dirtyNormals = geometry.normalsNeedUpdate,
-
-		customAttributes = geometry.__webglCustomAttributesList;
-
-		if ( dirtyVertices ) {
-
-			for ( v = 0; v < vl; v ++ ) {
-
-				vertex = vertices[ v ];
-
-				offset = v * 3;
-
-				vertexArray[ offset ]     = vertex.x;
-				vertexArray[ offset + 1 ] = vertex.y;
-				vertexArray[ offset + 2 ] = vertex.z;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
-		}
-
-		if ( dirtyColors ) {
-
-			for ( c = 0; c < cl; c ++ ) {
-
-				color = colors[ c ];
-
-				offset = c * 3;
-
-				colorArray[ offset ]     = color.r;
-				colorArray[ offset + 1 ] = color.g;
-				colorArray[ offset + 2 ] = color.b;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
-		}
-
-		if ( dirtyNormals ) {
-
-			for ( n = 0; n < nl; n ++ ) {
-
-				normal = normals[ n ];
-
-				offset = n * 3;
-
-				normalArray[ offset ]     = normal.x;
-				normalArray[ offset + 1 ] = normal.y;
-				normalArray[ offset + 2 ] = normal.z;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglNormalBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
-
-		}
-
-		if ( customAttributes ) {
-
-			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-				customAttribute = customAttributes[ i ];
-
-				if ( customAttribute.needsUpdate &&
-					 ( customAttribute.boundTo === undefined ||
-					   customAttribute.boundTo === "vertices" ) ) {
-
-					offset = 0;
-
-					cal = customAttribute.value.length;
-
-					if ( customAttribute.size === 1 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							customAttribute.array[ ca ] = customAttribute.value[ ca ];
-
-						}
-
-					} else if ( customAttribute.size === 2 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							value = customAttribute.value[ ca ];
-
-							customAttribute.array[ offset ] 	= value.x;
-							customAttribute.array[ offset + 1 ] = value.y;
-
-							offset += 2;
-
-						}
-
-					} else if ( customAttribute.size === 3 ) {
-
-						if ( customAttribute.type === "c" ) {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ] 	= value.r;
-								customAttribute.array[ offset + 1 ] = value.g;
-								customAttribute.array[ offset + 2 ] = value.b;
-
-								offset += 3;
-
-							}
-
-						} else {
-
-							for ( ca = 0; ca < cal; ca ++ ) {
-
-								value = customAttribute.value[ ca ];
-
-								customAttribute.array[ offset ] 	= value.x;
-								customAttribute.array[ offset + 1 ] = value.y;
-								customAttribute.array[ offset + 2 ] = value.z;
-
-								offset += 3;
-
-							}
-
-						}
-
-					} else if ( customAttribute.size === 4 ) {
-
-						for ( ca = 0; ca < cal; ca ++ ) {
-
-							value = customAttribute.value[ ca ];
-
-							customAttribute.array[ offset ] 	 = value.x;
-							customAttribute.array[ offset + 1  ] = value.y;
-							customAttribute.array[ offset + 2  ] = value.z;
-							customAttribute.array[ offset + 3  ] = value.w;
-
-							offset += 4;
-
-						}
-
-					}
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
-					_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
-
-		if ( ! geometryGroup.__inittedArrays ) {
-
-			return;
-
-		}
-
-		var normalType = bufferGuessNormalType( material ),
-		vertexColorType = bufferGuessVertexColorType( material ),
-		uvType = bufferGuessUVType( material ),
-
-		needsSmoothNormals = ( normalType === THREE.SmoothShading );
-
-		var f, fl, fi, face,
-		vertexNormals, faceNormal, normal,
-		vertexColors, faceColor,
-		vertexTangents,
-		uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
-		c1, c2, c3, c4,
-		sw1, sw2, sw3, sw4,
-		si1, si2, si3, si4,
-		sa1, sa2, sa3, sa4,
-		sb1, sb2, sb3, sb4,
-		m, ml, i, il,
-		vn, uvi, uv2i,
-		vk, vkl, vka,
-		nka, chf, faceVertexNormals,
-		a,
-
-		vertexIndex = 0,
-
-		offset = 0,
-		offset_uv = 0,
-		offset_uv2 = 0,
-		offset_face = 0,
-		offset_normal = 0,
-		offset_tangent = 0,
-		offset_line = 0,
-		offset_color = 0,
-		offset_skin = 0,
-		offset_morphTarget = 0,
-		offset_custom = 0,
-		offset_customSrc = 0,
-
-		value,
-
-		vertexArray = geometryGroup.__vertexArray,
-		uvArray = geometryGroup.__uvArray,
-		uv2Array = geometryGroup.__uv2Array,
-		normalArray = geometryGroup.__normalArray,
-		tangentArray = geometryGroup.__tangentArray,
-		colorArray = geometryGroup.__colorArray,
-
-		skinIndexArray = geometryGroup.__skinIndexArray,
-		skinWeightArray = geometryGroup.__skinWeightArray,
-
-		morphTargetsArrays = geometryGroup.__morphTargetsArrays,
-		morphNormalsArrays = geometryGroup.__morphNormalsArrays,
-
-		customAttributes = geometryGroup.__webglCustomAttributesList,
-		customAttribute,
-
-		faceArray = geometryGroup.__faceArray,
-		lineArray = geometryGroup.__lineArray,
-
-		geometry = object.geometry, // this is shared for all chunks
-
-		dirtyVertices = geometry.verticesNeedUpdate,
-		dirtyElements = geometry.elementsNeedUpdate,
-		dirtyUvs = geometry.uvsNeedUpdate,
-		dirtyNormals = geometry.normalsNeedUpdate,
-		dirtyTangents = geometry.tangentsNeedUpdate,
-		dirtyColors = geometry.colorsNeedUpdate,
-		dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
-
-		vertices = geometry.vertices,
-		chunk_faces3 = geometryGroup.faces3,
-		chunk_faces4 = geometryGroup.faces4,
-		obj_faces = geometry.faces,
-
-		obj_uvs  = geometry.faceVertexUvs[ 0 ],
-		obj_uvs2 = geometry.faceVertexUvs[ 1 ],
-
-		obj_colors = geometry.colors,
-
-		obj_skinIndices = geometry.skinIndices,
-		obj_skinWeights = geometry.skinWeights,
-
-		morphTargets = geometry.morphTargets,
-		morphNormals = geometry.morphNormals;
-
-		if ( dirtyVertices ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces3[ f ] ];
-
-				v1 = vertices[ face.a ];
-				v2 = vertices[ face.b ];
-				v3 = vertices[ face.c ];
-
-				vertexArray[ offset ]     = v1.x;
-				vertexArray[ offset + 1 ] = v1.y;
-				vertexArray[ offset + 2 ] = v1.z;
-
-				vertexArray[ offset + 3 ] = v2.x;
-				vertexArray[ offset + 4 ] = v2.y;
-				vertexArray[ offset + 5 ] = v2.z;
-
-				vertexArray[ offset + 6 ] = v3.x;
-				vertexArray[ offset + 7 ] = v3.y;
-				vertexArray[ offset + 8 ] = v3.z;
-
-				offset += 9;
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces4[ f ] ];
-
-				v1 = vertices[ face.a ];
-				v2 = vertices[ face.b ];
-				v3 = vertices[ face.c ];
-				v4 = vertices[ face.d ];
-
-				vertexArray[ offset ]     = v1.x;
-				vertexArray[ offset + 1 ] = v1.y;
-				vertexArray[ offset + 2 ] = v1.z;
-
-				vertexArray[ offset + 3 ] = v2.x;
-				vertexArray[ offset + 4 ] = v2.y;
-				vertexArray[ offset + 5 ] = v2.z;
-
-				vertexArray[ offset + 6 ] = v3.x;
-				vertexArray[ offset + 7 ] = v3.y;
-				vertexArray[ offset + 8 ] = v3.z;
-
-				vertexArray[ offset + 9 ]  = v4.x;
-				vertexArray[ offset + 10 ] = v4.y;
-				vertexArray[ offset + 11 ] = v4.z;
-
-				offset += 12;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
-		}
-
-		if ( dirtyMorphTargets ) {
-
-			for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
-
-				offset_morphTarget = 0;
-
-				for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-					chf = chunk_faces3[ f ];
-					face = obj_faces[ chf ];
-
-					// morph positions
-
-					v1 = morphTargets[ vk ].vertices[ face.a ];
-					v2 = morphTargets[ vk ].vertices[ face.b ];
-					v3 = morphTargets[ vk ].vertices[ face.c ];
-
-					vka = morphTargetsArrays[ vk ];
-
-					vka[ offset_morphTarget ] 	  = v1.x;
-					vka[ offset_morphTarget + 1 ] = v1.y;
-					vka[ offset_morphTarget + 2 ] = v1.z;
-
-					vka[ offset_morphTarget + 3 ] = v2.x;
-					vka[ offset_morphTarget + 4 ] = v2.y;
-					vka[ offset_morphTarget + 5 ] = v2.z;
-
-					vka[ offset_morphTarget + 6 ] = v3.x;
-					vka[ offset_morphTarget + 7 ] = v3.y;
-					vka[ offset_morphTarget + 8 ] = v3.z;
-
-					// morph normals
-
-					if ( material.morphNormals ) {
-
-						if ( needsSmoothNormals ) {
-
-							faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
-
-							n1 = faceVertexNormals.a;
-							n2 = faceVertexNormals.b;
-							n3 = faceVertexNormals.c;
-
-						} else {
-
-							n1 = morphNormals[ vk ].faceNormals[ chf ];
-							n2 = n1;
-							n3 = n1;
-
-						}
-
-						nka = morphNormalsArrays[ vk ];
-
-						nka[ offset_morphTarget ] 	  = n1.x;
-						nka[ offset_morphTarget + 1 ] = n1.y;
-						nka[ offset_morphTarget + 2 ] = n1.z;
-
-						nka[ offset_morphTarget + 3 ] = n2.x;
-						nka[ offset_morphTarget + 4 ] = n2.y;
-						nka[ offset_morphTarget + 5 ] = n2.z;
-
-						nka[ offset_morphTarget + 6 ] = n3.x;
-						nka[ offset_morphTarget + 7 ] = n3.y;
-						nka[ offset_morphTarget + 8 ] = n3.z;
-
-					}
-
-					//
-
-					offset_morphTarget += 9;
-
-				}
-
-				for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-					chf = chunk_faces4[ f ];
-					face = obj_faces[ chf ];
-
-					// morph positions
-
-					v1 = morphTargets[ vk ].vertices[ face.a ];
-					v2 = morphTargets[ vk ].vertices[ face.b ];
-					v3 = morphTargets[ vk ].vertices[ face.c ];
-					v4 = morphTargets[ vk ].vertices[ face.d ];
-
-					vka = morphTargetsArrays[ vk ];
-
-					vka[ offset_morphTarget ] 	  = v1.x;
-					vka[ offset_morphTarget + 1 ] = v1.y;
-					vka[ offset_morphTarget + 2 ] = v1.z;
-
-					vka[ offset_morphTarget + 3 ] = v2.x;
-					vka[ offset_morphTarget + 4 ] = v2.y;
-					vka[ offset_morphTarget + 5 ] = v2.z;
-
-					vka[ offset_morphTarget + 6 ] = v3.x;
-					vka[ offset_morphTarget + 7 ] = v3.y;
-					vka[ offset_morphTarget + 8 ] = v3.z;
-
-					vka[ offset_morphTarget + 9 ]  = v4.x;
-					vka[ offset_morphTarget + 10 ] = v4.y;
-					vka[ offset_morphTarget + 11 ] = v4.z;
-
-					// morph normals
-
-					if ( material.morphNormals ) {
-
-						if ( needsSmoothNormals ) {
-
-							faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
-
-							n1 = faceVertexNormals.a;
-							n2 = faceVertexNormals.b;
-							n3 = faceVertexNormals.c;
-							n4 = faceVertexNormals.d;
-
-						} else {
-
-							n1 = morphNormals[ vk ].faceNormals[ chf ];
-							n2 = n1;
-							n3 = n1;
-							n4 = n1;
-
-						}
-
-						nka = morphNormalsArrays[ vk ];
-
-						nka[ offset_morphTarget ] 	  = n1.x;
-						nka[ offset_morphTarget + 1 ] = n1.y;
-						nka[ offset_morphTarget + 2 ] = n1.z;
-
-						nka[ offset_morphTarget + 3 ] = n2.x;
-						nka[ offset_morphTarget + 4 ] = n2.y;
-						nka[ offset_morphTarget + 5 ] = n2.z;
-
-						nka[ offset_morphTarget + 6 ] = n3.x;
-						nka[ offset_morphTarget + 7 ] = n3.y;
-						nka[ offset_morphTarget + 8 ] = n3.z;
-
-						nka[ offset_morphTarget + 9 ]  = n4.x;
-						nka[ offset_morphTarget + 10 ] = n4.y;
-						nka[ offset_morphTarget + 11 ] = n4.z;
-
-					}
-
-					//
-
-					offset_morphTarget += 12;
-
-				}
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
-				_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
-
-				if ( material.morphNormals ) {
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
-					_gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );
-
-				}
-
-			}
-
-		}
-
-		if ( obj_skinWeights.length ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces3[ f ]	];
-
-				// weights
-
-				sw1 = obj_skinWeights[ face.a ];
-				sw2 = obj_skinWeights[ face.b ];
-				sw3 = obj_skinWeights[ face.c ];
-
-				skinWeightArray[ offset_skin ]     = sw1.x;
-				skinWeightArray[ offset_skin + 1 ] = sw1.y;
-				skinWeightArray[ offset_skin + 2 ] = sw1.z;
-				skinWeightArray[ offset_skin + 3 ] = sw1.w;
-
-				skinWeightArray[ offset_skin + 4 ] = sw2.x;
-				skinWeightArray[ offset_skin + 5 ] = sw2.y;
-				skinWeightArray[ offset_skin + 6 ] = sw2.z;
-				skinWeightArray[ offset_skin + 7 ] = sw2.w;
-
-				skinWeightArray[ offset_skin + 8 ]  = sw3.x;
-				skinWeightArray[ offset_skin + 9 ]  = sw3.y;
-				skinWeightArray[ offset_skin + 10 ] = sw3.z;
-				skinWeightArray[ offset_skin + 11 ] = sw3.w;
-
-				// indices
-
-				si1 = obj_skinIndices[ face.a ];
-				si2 = obj_skinIndices[ face.b ];
-				si3 = obj_skinIndices[ face.c ];
-
-				skinIndexArray[ offset_skin ]     = si1.x;
-				skinIndexArray[ offset_skin + 1 ] = si1.y;
-				skinIndexArray[ offset_skin + 2 ] = si1.z;
-				skinIndexArray[ offset_skin + 3 ] = si1.w;
-
-				skinIndexArray[ offset_skin + 4 ] = si2.x;
-				skinIndexArray[ offset_skin + 5 ] = si2.y;
-				skinIndexArray[ offset_skin + 6 ] = si2.z;
-				skinIndexArray[ offset_skin + 7 ] = si2.w;
-
-				skinIndexArray[ offset_skin + 8 ]  = si3.x;
-				skinIndexArray[ offset_skin + 9 ]  = si3.y;
-				skinIndexArray[ offset_skin + 10 ] = si3.z;
-				skinIndexArray[ offset_skin + 11 ] = si3.w;
-
-				offset_skin += 12;
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces4[ f ] ];
-
-				// weights
-
-				sw1 = obj_skinWeights[ face.a ];
-				sw2 = obj_skinWeights[ face.b ];
-				sw3 = obj_skinWeights[ face.c ];
-				sw4 = obj_skinWeights[ face.d ];
-
-				skinWeightArray[ offset_skin ]     = sw1.x;
-				skinWeightArray[ offset_skin + 1 ] = sw1.y;
-				skinWeightArray[ offset_skin + 2 ] = sw1.z;
-				skinWeightArray[ offset_skin + 3 ] = sw1.w;
-
-				skinWeightArray[ offset_skin + 4 ] = sw2.x;
-				skinWeightArray[ offset_skin + 5 ] = sw2.y;
-				skinWeightArray[ offset_skin + 6 ] = sw2.z;
-				skinWeightArray[ offset_skin + 7 ] = sw2.w;
-
-				skinWeightArray[ offset_skin + 8 ]  = sw3.x;
-				skinWeightArray[ offset_skin + 9 ]  = sw3.y;
-				skinWeightArray[ offset_skin + 10 ] = sw3.z;
-				skinWeightArray[ offset_skin + 11 ] = sw3.w;
-
-				skinWeightArray[ offset_skin + 12 ] = sw4.x;
-				skinWeightArray[ offset_skin + 13 ] = sw4.y;
-				skinWeightArray[ offset_skin + 14 ] = sw4.z;
-				skinWeightArray[ offset_skin + 15 ] = sw4.w;
-
-				// indices
-
-				si1 = obj_skinIndices[ face.a ];
-				si2 = obj_skinIndices[ face.b ];
-				si3 = obj_skinIndices[ face.c ];
-				si4 = obj_skinIndices[ face.d ];
-
-				skinIndexArray[ offset_skin ]     = si1.x;
-				skinIndexArray[ offset_skin + 1 ] = si1.y;
-				skinIndexArray[ offset_skin + 2 ] = si1.z;
-				skinIndexArray[ offset_skin + 3 ] = si1.w;
-
-				skinIndexArray[ offset_skin + 4 ] = si2.x;
-				skinIndexArray[ offset_skin + 5 ] = si2.y;
-				skinIndexArray[ offset_skin + 6 ] = si2.z;
-				skinIndexArray[ offset_skin + 7 ] = si2.w;
-
-				skinIndexArray[ offset_skin + 8 ]  = si3.x;
-				skinIndexArray[ offset_skin + 9 ]  = si3.y;
-				skinIndexArray[ offset_skin + 10 ] = si3.z;
-				skinIndexArray[ offset_skin + 11 ] = si3.w;
-
-				skinIndexArray[ offset_skin + 12 ] = si4.x;
-				skinIndexArray[ offset_skin + 13 ] = si4.y;
-				skinIndexArray[ offset_skin + 14 ] = si4.z;
-				skinIndexArray[ offset_skin + 15 ] = si4.w;
-
-				offset_skin += 16;
-
-			}
-
-			if ( offset_skin > 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
-
-			}
-
-		}
-
-		if ( dirtyColors && vertexColorType ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces3[ f ]	];
-
-				vertexColors = face.vertexColors;
-				faceColor = face.color;
-
-				if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {
-
-					c1 = vertexColors[ 0 ];
-					c2 = vertexColors[ 1 ];
-					c3 = vertexColors[ 2 ];
-
-				} else {
-
-					c1 = faceColor;
-					c2 = faceColor;
-					c3 = faceColor;
-
-				}
-
-				colorArray[ offset_color ]     = c1.r;
-				colorArray[ offset_color + 1 ] = c1.g;
-				colorArray[ offset_color + 2 ] = c1.b;
-
-				colorArray[ offset_color + 3 ] = c2.r;
-				colorArray[ offset_color + 4 ] = c2.g;
-				colorArray[ offset_color + 5 ] = c2.b;
-
-				colorArray[ offset_color + 6 ] = c3.r;
-				colorArray[ offset_color + 7 ] = c3.g;
-				colorArray[ offset_color + 8 ] = c3.b;
-
-				offset_color += 9;
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces4[ f ] ];
-
-				vertexColors = face.vertexColors;
-				faceColor = face.color;
-
-				if ( vertexColors.length === 4 && vertexColorType === THREE.VertexColors ) {
-
-					c1 = vertexColors[ 0 ];
-					c2 = vertexColors[ 1 ];
-					c3 = vertexColors[ 2 ];
-					c4 = vertexColors[ 3 ];
-
-				} else {
-
-					c1 = faceColor;
-					c2 = faceColor;
-					c3 = faceColor;
-					c4 = faceColor;
-
-				}
-
-				colorArray[ offset_color ]     = c1.r;
-				colorArray[ offset_color + 1 ] = c1.g;
-				colorArray[ offset_color + 2 ] = c1.b;
-
-				colorArray[ offset_color + 3 ] = c2.r;
-				colorArray[ offset_color + 4 ] = c2.g;
-				colorArray[ offset_color + 5 ] = c2.b;
-
-				colorArray[ offset_color + 6 ] = c3.r;
-				colorArray[ offset_color + 7 ] = c3.g;
-				colorArray[ offset_color + 8 ] = c3.b;
-
-				colorArray[ offset_color + 9 ]  = c4.r;
-				colorArray[ offset_color + 10 ] = c4.g;
-				colorArray[ offset_color + 11 ] = c4.b;
-
-				offset_color += 12;
-
-			}
-
-			if ( offset_color > 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
-			}
-
-		}
-
-		if ( dirtyTangents && geometry.hasTangents ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces3[ f ]	];
-
-				vertexTangents = face.vertexTangents;
-
-				t1 = vertexTangents[ 0 ];
-				t2 = vertexTangents[ 1 ];
-				t3 = vertexTangents[ 2 ];
-
-				tangentArray[ offset_tangent ]     = t1.x;
-				tangentArray[ offset_tangent + 1 ] = t1.y;
-				tangentArray[ offset_tangent + 2 ] = t1.z;
-				tangentArray[ offset_tangent + 3 ] = t1.w;
-
-				tangentArray[ offset_tangent + 4 ] = t2.x;
-				tangentArray[ offset_tangent + 5 ] = t2.y;
-				tangentArray[ offset_tangent + 6 ] = t2.z;
-				tangentArray[ offset_tangent + 7 ] = t2.w;
-
-				tangentArray[ offset_tangent + 8 ]  = t3.x;
-				tangentArray[ offset_tangent + 9 ]  = t3.y;
-				tangentArray[ offset_tangent + 10 ] = t3.z;
-				tangentArray[ offset_tangent + 11 ] = t3.w;
-
-				offset_tangent += 12;
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces4[ f ] ];
-
-				vertexTangents = face.vertexTangents;
-
-				t1 = vertexTangents[ 0 ];
-				t2 = vertexTangents[ 1 ];
-				t3 = vertexTangents[ 2 ];
-				t4 = vertexTangents[ 3 ];
-
-				tangentArray[ offset_tangent ]     = t1.x;
-				tangentArray[ offset_tangent + 1 ] = t1.y;
-				tangentArray[ offset_tangent + 2 ] = t1.z;
-				tangentArray[ offset_tangent + 3 ] = t1.w;
-
-				tangentArray[ offset_tangent + 4 ] = t2.x;
-				tangentArray[ offset_tangent + 5 ] = t2.y;
-				tangentArray[ offset_tangent + 6 ] = t2.z;
-				tangentArray[ offset_tangent + 7 ] = t2.w;
-
-				tangentArray[ offset_tangent + 8 ]  = t3.x;
-				tangentArray[ offset_tangent + 9 ]  = t3.y;
-				tangentArray[ offset_tangent + 10 ] = t3.z;
-				tangentArray[ offset_tangent + 11 ] = t3.w;
-
-				tangentArray[ offset_tangent + 12 ] = t4.x;
-				tangentArray[ offset_tangent + 13 ] = t4.y;
-				tangentArray[ offset_tangent + 14 ] = t4.z;
-				tangentArray[ offset_tangent + 15 ] = t4.w;
-
-				offset_tangent += 16;
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
-
-		}
-
-		if ( dirtyNormals && normalType ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces3[ f ]	];
-
-				vertexNormals = face.vertexNormals;
-				faceNormal = face.normal;
-
-				if ( vertexNormals.length === 3 && needsSmoothNormals ) {
-
-					for ( i = 0; i < 3; i ++ ) {
-
-						vn = vertexNormals[ i ];
-
-						normalArray[ offset_normal ]     = vn.x;
-						normalArray[ offset_normal + 1 ] = vn.y;
-						normalArray[ offset_normal + 2 ] = vn.z;
-
-						offset_normal += 3;
-
-					}
-
-				} else {
-
-					for ( i = 0; i < 3; i ++ ) {
-
-						normalArray[ offset_normal ]     = faceNormal.x;
-						normalArray[ offset_normal + 1 ] = faceNormal.y;
-						normalArray[ offset_normal + 2 ] = faceNormal.z;
-
-						offset_normal += 3;
-
-					}
-
-				}
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				face = obj_faces[ chunk_faces4[ f ] ];
-
-				vertexNormals = face.vertexNormals;
-				faceNormal = face.normal;
-
-				if ( vertexNormals.length === 4 && needsSmoothNormals ) {
-
-					for ( i = 0; i < 4; i ++ ) {
-
-						vn = vertexNormals[ i ];
-
-						normalArray[ offset_normal ]     = vn.x;
-						normalArray[ offset_normal + 1 ] = vn.y;
-						normalArray[ offset_normal + 2 ] = vn.z;
-
-						offset_normal += 3;
-
-					}
-
-				} else {
-
-					for ( i = 0; i < 4; i ++ ) {
-
-						normalArray[ offset_normal ]     = faceNormal.x;
-						normalArray[ offset_normal + 1 ] = faceNormal.y;
-						normalArray[ offset_normal + 2 ] = faceNormal.z;
-
-						offset_normal += 3;
-
-					}
-
-				}
-
-			}
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
-
-		}
-
-		if ( dirtyUvs && obj_uvs && uvType ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				fi = chunk_faces3[ f ];
-
-				uv = obj_uvs[ fi ];
-
-				if ( uv === undefined ) continue;
-
-				for ( i = 0; i < 3; i ++ ) {
-
-					uvi = uv[ i ];
-
-					uvArray[ offset_uv ]     = uvi.x;
-					uvArray[ offset_uv + 1 ] = uvi.y;
-
-					offset_uv += 2;
-
-				}
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				fi = chunk_faces4[ f ];
-
-				uv = obj_uvs[ fi ];
-
-				if ( uv === undefined ) continue;
-
-				for ( i = 0; i < 4; i ++ ) {
-
-					uvi = uv[ i ];
-
-					uvArray[ offset_uv ]     = uvi.x;
-					uvArray[ offset_uv + 1 ] = uvi.y;
-
-					offset_uv += 2;
-
-				}
-
-			}
-
-			if ( offset_uv > 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
-
-			}
-
-		}
-
-		if ( dirtyUvs && obj_uvs2 && uvType ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				fi = chunk_faces3[ f ];
-
-				uv2 = obj_uvs2[ fi ];
-
-				if ( uv2 === undefined ) continue;
-
-				for ( i = 0; i < 3; i ++ ) {
-
-					uv2i = uv2[ i ];
-
-					uv2Array[ offset_uv2 ]     = uv2i.x;
-					uv2Array[ offset_uv2 + 1 ] = uv2i.y;
-
-					offset_uv2 += 2;
-
-				}
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				fi = chunk_faces4[ f ];
-
-				uv2 = obj_uvs2[ fi ];
-
-				if ( uv2 === undefined ) continue;
-
-				for ( i = 0; i < 4; i ++ ) {
-
-					uv2i = uv2[ i ];
-
-					uv2Array[ offset_uv2 ]     = uv2i.x;
-					uv2Array[ offset_uv2 + 1 ] = uv2i.y;
-
-					offset_uv2 += 2;
-
-				}
-
-			}
-
-			if ( offset_uv2 > 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
-
-			}
-
-		}
-
-		if ( dirtyElements ) {
-
-			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-				faceArray[ offset_face ] 	 = vertexIndex;
-				faceArray[ offset_face + 1 ] = vertexIndex + 1;
-				faceArray[ offset_face + 2 ] = vertexIndex + 2;
-
-				offset_face += 3;
-
-				lineArray[ offset_line ]     = vertexIndex;
-				lineArray[ offset_line + 1 ] = vertexIndex + 1;
-
-				lineArray[ offset_line + 2 ] = vertexIndex;
-				lineArray[ offset_line + 3 ] = vertexIndex + 2;
-
-				lineArray[ offset_line + 4 ] = vertexIndex + 1;
-				lineArray[ offset_line + 5 ] = vertexIndex + 2;
-
-				offset_line += 6;
-
-				vertexIndex += 3;
-
-			}
-
-			for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-				faceArray[ offset_face ]     = vertexIndex;
-				faceArray[ offset_face + 1 ] = vertexIndex + 1;
-				faceArray[ offset_face + 2 ] = vertexIndex + 3;
-
-				faceArray[ offset_face + 3 ] = vertexIndex + 1;
-				faceArray[ offset_face + 4 ] = vertexIndex + 2;
-				faceArray[ offset_face + 5 ] = vertexIndex + 3;
-
-				offset_face += 6;
-
-				lineArray[ offset_line ]     = vertexIndex;
-				lineArray[ offset_line + 1 ] = vertexIndex + 1;
-
-				lineArray[ offset_line + 2 ] = vertexIndex;
-				lineArray[ offset_line + 3 ] = vertexIndex + 3;
-
-				lineArray[ offset_line + 4 ] = vertexIndex + 1;
-				lineArray[ offset_line + 5 ] = vertexIndex + 2;
-
-				lineArray[ offset_line + 6 ] = vertexIndex + 2;
-				lineArray[ offset_line + 7 ] = vertexIndex + 3;
-
-				offset_line += 8;
-
-				vertexIndex += 4;
-
-			}
-
-			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
-			_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
-
-			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
-			_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
-
-		}
-
-		if ( customAttributes ) {
-
-			for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
-				customAttribute = customAttributes[ i ];
-
-				if ( ! customAttribute.__original.needsUpdate ) continue;
-
-				offset_custom = 0;
-				offset_customSrc = 0;
-
-				if ( customAttribute.size === 1 ) {
-
-					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces3[ f ]	];
-
-							customAttribute.array[ offset_custom ] 	   = customAttribute.value[ face.a ];
-							customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
-							customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
-
-							offset_custom += 3;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces4[ f ] ];
-
-							customAttribute.array[ offset_custom ] 	   = customAttribute.value[ face.a ];
-							customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
-							customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
-							customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];
-
-							offset_custom += 4;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faces" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							customAttribute.array[ offset_custom ] 	   = value;
-							customAttribute.array[ offset_custom + 1 ] = value;
-							customAttribute.array[ offset_custom + 2 ] = value;
-
-							offset_custom += 3;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							customAttribute.array[ offset_custom ] 	   = value;
-							customAttribute.array[ offset_custom + 1 ] = value;
-							customAttribute.array[ offset_custom + 2 ] = value;
-							customAttribute.array[ offset_custom + 3 ] = value;
-
-							offset_custom += 4;
-
-						}
-
-					}
-
-				} else if ( customAttribute.size === 2 ) {
-
-					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces3[ f ]	];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-
-							customAttribute.array[ offset_custom ] 	   = v1.x;
-							customAttribute.array[ offset_custom + 1 ] = v1.y;
-
-							customAttribute.array[ offset_custom + 2 ] = v2.x;
-							customAttribute.array[ offset_custom + 3 ] = v2.y;
-
-							customAttribute.array[ offset_custom + 4 ] = v3.x;
-							customAttribute.array[ offset_custom + 5 ] = v3.y;
-
-							offset_custom += 6;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces4[ f ] ];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-							v4 = customAttribute.value[ face.d ];
-
-							customAttribute.array[ offset_custom ] 	   = v1.x;
-							customAttribute.array[ offset_custom + 1 ] = v1.y;
-
-							customAttribute.array[ offset_custom + 2 ] = v2.x;
-							customAttribute.array[ offset_custom + 3 ] = v2.y;
-
-							customAttribute.array[ offset_custom + 4 ] = v3.x;
-							customAttribute.array[ offset_custom + 5 ] = v3.y;
-
-							customAttribute.array[ offset_custom + 6 ] = v4.x;
-							customAttribute.array[ offset_custom + 7 ] = v4.y;
-
-							offset_custom += 8;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faces" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-
-							customAttribute.array[ offset_custom ] 	   = v1.x;
-							customAttribute.array[ offset_custom + 1 ] = v1.y;
-
-							customAttribute.array[ offset_custom + 2 ] = v2.x;
-							customAttribute.array[ offset_custom + 3 ] = v2.y;
-
-							customAttribute.array[ offset_custom + 4 ] = v3.x;
-							customAttribute.array[ offset_custom + 5 ] = v3.y;
-
-							offset_custom += 6;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-							v4 = value;
-
-							customAttribute.array[ offset_custom ] 	   = v1.x;
-							customAttribute.array[ offset_custom + 1 ] = v1.y;
-
-							customAttribute.array[ offset_custom + 2 ] = v2.x;
-							customAttribute.array[ offset_custom + 3 ] = v2.y;
-
-							customAttribute.array[ offset_custom + 4 ] = v3.x;
-							customAttribute.array[ offset_custom + 5 ] = v3.y;
-
-							customAttribute.array[ offset_custom + 6 ] = v4.x;
-							customAttribute.array[ offset_custom + 7 ] = v4.y;
-
-							offset_custom += 8;
-
-						}
-
-					}
-
-				} else if ( customAttribute.size === 3 ) {
-
-					var pp;
-
-					if ( customAttribute.type === "c" ) {
-
-						pp = [ "r", "g", "b" ];
-
-					} else {
-
-						pp = [ "x", "y", "z" ];
-
-					}
-
-					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces3[ f ]	];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
-							offset_custom += 9;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces4[ f ] ];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-							v4 = customAttribute.value[ face.d ];
-
-							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
-
-							offset_custom += 12;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faces" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
-							offset_custom += 9;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-							v4 = value;
-
-							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
-
-							offset_custom += 12;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faceVertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							v1 = value[ 0 ];
-							v2 = value[ 1 ];
-							v3 = value[ 2 ];
-
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
-							offset_custom += 9;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							v1 = value[ 0 ];
-							v2 = value[ 1 ];
-							v3 = value[ 2 ];
-							v4 = value[ 3 ];
-
-							customAttribute.array[ offset_custom  ] 	= v1[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];
-
-							customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
-							customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
-							customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
-
-							offset_custom += 12;
-
-						}
-
-					}
-
-				} else if ( customAttribute.size === 4 ) {
-
-					if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces3[ f ]	];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							offset_custom += 12;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							face = obj_faces[ chunk_faces4[ f ] ];
-
-							v1 = customAttribute.value[ face.a ];
-							v2 = customAttribute.value[ face.b ];
-							v3 = customAttribute.value[ face.c ];
-							v4 = customAttribute.value[ face.d ];
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							customAttribute.array[ offset_custom + 12 ] = v4.x;
-							customAttribute.array[ offset_custom + 13 ] = v4.y;
-							customAttribute.array[ offset_custom + 14 ] = v4.z;
-							customAttribute.array[ offset_custom + 15 ] = v4.w;
-
-							offset_custom += 16;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faces" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							offset_custom += 12;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							v1 = value;
-							v2 = value;
-							v3 = value;
-							v4 = value;
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							customAttribute.array[ offset_custom + 12 ] = v4.x;
-							customAttribute.array[ offset_custom + 13 ] = v4.y;
-							customAttribute.array[ offset_custom + 14 ] = v4.z;
-							customAttribute.array[ offset_custom + 15 ] = v4.w;
-
-							offset_custom += 16;
-
-						}
-
-					} else if ( customAttribute.boundTo === "faceVertices" ) {
-
-						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces3[ f ] ];
-
-							v1 = value[ 0 ];
-							v2 = value[ 1 ];
-							v3 = value[ 2 ];
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							offset_custom += 12;
-
-						}
-
-						for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
-
-							value = customAttribute.value[ chunk_faces4[ f ] ];
-
-							v1 = value[ 0 ];
-							v2 = value[ 1 ];
-							v3 = value[ 2 ];
-							v4 = value[ 3 ];
-
-							customAttribute.array[ offset_custom  ] 	= v1.x;
-							customAttribute.array[ offset_custom + 1  ] = v1.y;
-							customAttribute.array[ offset_custom + 2  ] = v1.z;
-							customAttribute.array[ offset_custom + 3  ] = v1.w;
-
-							customAttribute.array[ offset_custom + 4  ] = v2.x;
-							customAttribute.array[ offset_custom + 5  ] = v2.y;
-							customAttribute.array[ offset_custom + 6  ] = v2.z;
-							customAttribute.array[ offset_custom + 7  ] = v2.w;
-
-							customAttribute.array[ offset_custom + 8  ] = v3.x;
-							customAttribute.array[ offset_custom + 9  ] = v3.y;
-							customAttribute.array[ offset_custom + 10 ] = v3.z;
-							customAttribute.array[ offset_custom + 11 ] = v3.w;
-
-							customAttribute.array[ offset_custom + 12 ] = v4.x;
-							customAttribute.array[ offset_custom + 13 ] = v4.y;
-							customAttribute.array[ offset_custom + 14 ] = v4.z;
-							customAttribute.array[ offset_custom + 15 ] = v4.w;
-
-							offset_custom += 16;
-
-						}
-
-					}
-
-				}
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
-				_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
-			}
-
-		}
-
-		if ( dispose ) {
-
-			delete geometryGroup.__inittedArrays;
-			delete geometryGroup.__colorArray;
-			delete geometryGroup.__normalArray;
-			delete geometryGroup.__tangentArray;
-			delete geometryGroup.__uvArray;
-			delete geometryGroup.__uv2Array;
-			delete geometryGroup.__faceArray;
-			delete geometryGroup.__vertexArray;
-			delete geometryGroup.__lineArray;
-			delete geometryGroup.__skinIndexArray;
-			delete geometryGroup.__skinWeightArray;
-
-		}
-
-	};
-
-	function setDirectBuffers ( geometry, hint, dispose ) {
-
-		var attributes = geometry.attributes;
-
-		var attributeName, attributeItem;
-
-		for ( attributeName in attributes ) {
-
-			attributeItem = attributes[ attributeName ];
-
-			if ( attributeItem.needsUpdate ) {
-
-				if ( attributeName === 'index' ) {
-
-					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer );
-					_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint );
-
-				} else {
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
-					_gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint );
-
-				}
-
-				attributeItem.needsUpdate = false;
-
-			}
-
-			if ( dispose && ! attributeItem.dynamic ) {
-
-				delete attributeItem.array;
-
-			}
-
-		}
-
-	};
-
-	// Buffer rendering
-
-	this.renderBufferImmediate = function ( object, program, material ) {
-
-		if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
-		if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
-		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
-		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
-
-		if ( object.hasPositions ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
-			_gl.enableVertexAttribArray( program.attributes.position );
-			_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
-		}
-
-		if ( object.hasNormals ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
-
-			if ( material.shading === THREE.FlatShading ) {
-
-				var nx, ny, nz,
-					nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
-					normalArray,
-					i, il = object.count * 3;
-
-				for( i = 0; i < il; i += 9 ) {
-
-					normalArray = object.normalArray;
-
-					nax  = normalArray[ i ];
-					nay  = normalArray[ i + 1 ];
-					naz  = normalArray[ i + 2 ];
-
-					nbx  = normalArray[ i + 3 ];
-					nby  = normalArray[ i + 4 ];
-					nbz  = normalArray[ i + 5 ];
-
-					ncx  = normalArray[ i + 6 ];
-					ncy  = normalArray[ i + 7 ];
-					ncz  = normalArray[ i + 8 ];
-
-					nx = ( nax + nbx + ncx ) / 3;
-					ny = ( nay + nby + ncy ) / 3;
-					nz = ( naz + nbz + ncz ) / 3;
-
-					normalArray[ i ] 	 = nx;
-					normalArray[ i + 1 ] = ny;
-					normalArray[ i + 2 ] = nz;
-
-					normalArray[ i + 3 ] = nx;
-					normalArray[ i + 4 ] = ny;
-					normalArray[ i + 5 ] = nz;
-
-					normalArray[ i + 6 ] = nx;
-					normalArray[ i + 7 ] = ny;
-					normalArray[ i + 8 ] = nz;
-
-				}
-
-			}
-
-			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
-			_gl.enableVertexAttribArray( program.attributes.normal );
-			_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
-
-		}
-
-		if ( object.hasUvs && material.map ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
-			_gl.enableVertexAttribArray( program.attributes.uv );
-			_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
-
-		}
-
-		if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
-			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
-			_gl.enableVertexAttribArray( program.attributes.color );
-			_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
-
-		}
-
-		_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
-
-		object.count = 0;
-
-	};
-
-	this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
-
-		if ( material.visible === false ) return;
-
-		var program, programAttributes, linewidth, primitives, a, attribute, geometryAttributes;
-		var attributeItem, attributeName, attributePointer, attributeSize;
-
-		program = setProgram( camera, lights, fog, material, object );
-
-		programAttributes = program.attributes;
-		geometryAttributes = geometry.attributes;
-
-		var updateBuffers = false,
-			wireframeBit = material.wireframe ? 1 : 0,
-			geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
-
-		if ( geometryHash !== _currentGeometryGroupHash ) {
-
-			_currentGeometryGroupHash = geometryHash;
-			updateBuffers = true;
-
-		}
-
-		if ( updateBuffers ) {
-
-			disableAttributes();
-
-		}
-
-		// render mesh
-
-		if ( object instanceof THREE.Mesh ) {
-
-			var index = geometryAttributes[ "index" ];
-
-			// indexed triangles
-
-			if ( index ) {
-
-				var offsets = geometry.offsets;
-
-				// if there is more than 1 chunk
-				// must set attribute pointers to use new offsets for each chunk
-				// even if geometry and materials didn't change
-
-				if ( offsets.length > 1 ) updateBuffers = true;
-
-				for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
-					var startIndex = offsets[ i ].index;
-
-					if ( updateBuffers ) {
-
-						for ( attributeName in geometryAttributes ) {
-
-							if ( attributeName === 'index' ) continue;
-
-							attributePointer = programAttributes[ attributeName ];
-							attributeItem = geometryAttributes[ attributeName ];
-							attributeSize = attributeItem.itemSize;
-
-							if ( attributePointer >= 0 ) {
-
-								_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
-								enableAttribute( attributePointer );
-								_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32
-
-							}
-
-						}
-
-						// indices
-
-						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
-					}
-
-					// render indexed triangles
-
-					_gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16
-
-					_this.info.render.calls ++;
-					_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
-					_this.info.render.faces += offsets[ i ].count / 3;
-
-				}
-
-			// non-indexed triangles
-
-			} else {
-
-				if ( updateBuffers ) {
-
-					for ( attributeName in geometryAttributes ) {
-
-						if ( attributeName === 'index') continue;
-
-						attributePointer = programAttributes[ attributeName ];
-						attributeItem = geometryAttributes[ attributeName ];
-						attributeSize = attributeItem.itemSize;
-
-						if ( attributePointer >= 0 ) {
-
-							_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
-							enableAttribute( attributePointer );
-							_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
-
-						}
-
-					}
-
-				}
-
-				var position = geometry.attributes[ "position" ];
-
-				// render non-indexed triangles
-
-				_gl.drawArrays( _gl.TRIANGLES, 0, position.numItems / 3 );
-
-				_this.info.render.calls ++;
-				_this.info.render.vertices += position.numItems / 3;
-				_this.info.render.faces += position.numItems / 3 / 3;
-
-			}
-
-		// render particles
-
-		} else if ( object instanceof THREE.ParticleSystem ) {
-
-			if ( updateBuffers ) {
-
-				for ( attributeName in geometryAttributes ) {
-
-					attributePointer = programAttributes[ attributeName ];
-					attributeItem = geometryAttributes[ attributeName ];
-					attributeSize = attributeItem.itemSize;
-
-					if ( attributePointer >= 0 ) {
-
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
-						enableAttribute( attributePointer );
-						_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
-
-					}
-
-				}
-
-				var position = geometryAttributes[ "position" ];
-
-				// render particles
-
-				_gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 );
-
-				_this.info.render.calls ++;
-				_this.info.render.points += position.numItems / 3;
-
-			}
-
-		} else if ( object instanceof THREE.Line ) {
-
-			if ( updateBuffers ) {
-
-				for ( attributeName in geometryAttributes ) {
-
-					attributePointer = programAttributes[ attributeName ];
-					attributeItem = geometryAttributes[ attributeName ];
-					attributeSize = attributeItem.itemSize;
-
-					if ( attributePointer >= 0 ) {
-
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
-						enableAttribute( attributePointer );
-						_gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
-
-					}
-
-				}
-
-				// render lines
-
-				setLineWidth( material.linewidth );
-
-				var position = geometryAttributes[ "position" ];
-
-				_gl.drawArrays( _gl.LINE_STRIP, 0, position.numItems / 3 );
-
-				_this.info.render.calls ++;
-				_this.info.render.points += position.numItems;
-
-			}
-
-    	}
-
-	};
-
-	this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
-
-		if ( material.visible === false ) return;
-
-		var program, attributes, linewidth, primitives, a, attribute, i, il;
-
-		program = setProgram( camera, lights, fog, material, object );
-
-		attributes = program.attributes;
-
-		var updateBuffers = false,
-			wireframeBit = material.wireframe ? 1 : 0,
-			geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
-
-		if ( geometryGroupHash !== _currentGeometryGroupHash ) {
-
-			_currentGeometryGroupHash = geometryGroupHash;
-			updateBuffers = true;
-
-		}
-
-		if ( updateBuffers ) {
-
-			disableAttributes();
-
-		}
-
-		// vertices
-
-		if ( !material.morphTargets && attributes.position >= 0 ) {
-
-			if ( updateBuffers ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
-				enableAttribute( attributes.position );
-				_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-		} else {
-
-			if ( object.morphTargetBase ) {
-
-				setupMorphTargets( material, geometryGroup, object );
-
-			}
-
-		}
-
-
-		if ( updateBuffers ) {
-
-			// custom attributes
-
-			// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
-
-			if ( geometryGroup.__webglCustomAttributesList ) {
-
-				for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
-
-					attribute = geometryGroup.__webglCustomAttributesList[ i ];
-
-					if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
-
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
-						enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );
-						_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );
-
-					}
-
-				}
-
-			}
-
-
-			// colors
-
-			if ( attributes.color >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
-				enableAttribute( attributes.color );
-				_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			// normals
-
-			if ( attributes.normal >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
-				enableAttribute( attributes.normal );
-				_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			// tangents
-
-			if ( attributes.tangent >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
-				enableAttribute( attributes.tangent );
-				_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			// uvs
-
-			if ( attributes.uv >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
-				enableAttribute( attributes.uv );
-				_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			if ( attributes.uv2 >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
-				enableAttribute( attributes.uv2 );
-				_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			if ( material.skinning &&
-				 attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
-				enableAttribute( attributes.skinIndex );
-				_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
-				enableAttribute( attributes.skinWeight );
-				_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-			// line distances
-
-			if ( attributes.lineDistance >= 0 ) {
-
-				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );
-				enableAttribute( attributes.lineDistance );
-				_gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );
-
-			}
-
-		}
-
-		// render mesh
-
-		if ( object instanceof THREE.Mesh ) {
-
-			// wireframe
-
-			if ( material.wireframe ) {
-
-				setLineWidth( material.wireframeLinewidth );
-
-				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
-				_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );
-
-			// triangles
-
-			} else {
-
-				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
-				_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
-
-			}
-
-			_this.info.render.calls ++;
-			_this.info.render.vertices += geometryGroup.__webglFaceCount;
-			_this.info.render.faces += geometryGroup.__webglFaceCount / 3;
-
-		// render lines
-
-		} else if ( object instanceof THREE.Line ) {
-
-			primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
-
-			setLineWidth( material.linewidth );
-
-			_gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );
-
-			_this.info.render.calls ++;
-
-		// render particles
-
-		} else if ( object instanceof THREE.ParticleSystem ) {
-
-			_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
-
-			_this.info.render.calls ++;
-			_this.info.render.points += geometryGroup.__webglParticleCount;
-
-		// render ribbon
-
-		} else if ( object instanceof THREE.Ribbon ) {
-
-			_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount );
-
-			_this.info.render.calls ++;
-
-		}
-
-	};
-
-	function enableAttribute( attribute ) {
-
-		if ( ! _enabledAttributes[ attribute ] ) {
-
-			_gl.enableVertexAttribArray( attribute );
-			_enabledAttributes[ attribute ] = true;
-
-		}
-
-	};
-
-	function disableAttributes() {
-
-		for ( var attribute in _enabledAttributes ) {
-
-			if ( _enabledAttributes[ attribute ] ) {
-
-				_gl.disableVertexAttribArray( attribute );
-				_enabledAttributes[ attribute ] = false;
-
-			}
-
-		}
-
-	};
-
-	function setupMorphTargets ( material, geometryGroup, object ) {
-
-		// set base
-
-		var attributes = material.program.attributes;
-
-		if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
-			enableAttribute( attributes.position );
-			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
-		} else if ( attributes.position >= 0 ) {
-
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
-			enableAttribute( attributes.position );
-			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
-		}
-
-		if ( object.morphTargetForcedOrder.length ) {
-
-			// set forced order
-
-			var m = 0;
-			var order = object.morphTargetForcedOrder;
-			var influences = object.morphTargetInfluences;
-
-			while ( m < material.numSupportedMorphTargets && m < order.length ) {
-
-				if ( attributes[ "morphTarget" + m ] >= 0 ) {
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
-					enableAttribute( attributes[ "morphTarget" + m ] );
-					_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-				}
-
-				if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
-
-					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
-					enableAttribute( attributes[ "morphNormal" + m ] );
-					_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-				}
-
-				object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
-
-				m ++;
-			}
-
-		} else {
-
-			// find the most influencing
-
-			var influence, activeInfluenceIndices = [];
-			var influences = object.morphTargetInfluences;
-			var i, il = influences.length;
-
-			for ( i = 0; i < il; i ++ ) {
-
-				influence = influences[ i ];
-
-				if ( influence > 0 ) {
-
-					activeInfluenceIndices.push( [ influence, i ] );
-
-				}
-
-			}
-
-			if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
-
-				activeInfluenceIndices.sort( numericalSort );
-				activeInfluenceIndices.length = material.numSupportedMorphTargets;
-
-			} else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
-
-				activeInfluenceIndices.sort( numericalSort );
-
-			} else if ( activeInfluenceIndices.length === 0 ) {
-
-				activeInfluenceIndices.push( [ 0, 0 ] );
-
-			};
-
-			var influenceIndex, m = 0;
-
-			while ( m < material.numSupportedMorphTargets ) {
-
-				if ( activeInfluenceIndices[ m ] ) {
-
-					influenceIndex = activeInfluenceIndices[ m ][ 1 ];
-
-					if ( attributes[ "morphTarget" + m ] >= 0 ) {
-
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );
-						enableAttribute( attributes[ "morphTarget" + m ] );
-						_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-					}
-
-					if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
-
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
-						enableAttribute( attributes[ "morphNormal" + m ] );
-						_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-
-					}
-
-					object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
-
-				} else {
-
-					/*
-					_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-					if ( material.morphNormals ) {
-
-						_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
-					}
-					*/
-
-					object.__webglMorphTargetInfluences[ m ] = 0;
-
-				}
-
-				m ++;
-
-			}
-
-		}
-
-		// load updated influences uniform
-
-		if ( material.program.uniforms.morphTargetInfluences !== null ) {
-
-			_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
-
-		}
-
-	};
-
-	// Sorting
-
-	function painterSortStable ( a, b ) {
-
-		if ( a.z !== b.z ) {
-
-			return b.z - a.z;
-
-		} else {
-
-			return a.id - b.id;
-
-		}
-
-	};
-
-	function numericalSort ( a, b ) {
-
-		return b[ 0 ] - a[ 0 ];
-
-	};
-
-
-	// Rendering
-
-	this.render = function ( scene, camera, renderTarget, forceClear ) {
-
-		if ( camera instanceof THREE.Camera === false ) {
-
-			console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
-			return;
-
-		}
-
-		var i, il,
-
-		webglObject, object,
-		renderList,
-
-		lights = scene.__lights,
-		fog = scene.fog;
-
-		// reset caching for this frame
-
-		_currentMaterialId = -1;
-		_lightsNeedUpdate = true;
-
-		// update scene graph
-
-		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-
-		// update camera matrices and frustum
-
-		if ( camera.parent === undefined ) camera.updateMatrixWorld();
-
-		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
-		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
-		_frustum.setFromMatrix( _projScreenMatrix );
-
-		// update WebGL objects
-
-		if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
-
-		// custom render plugins (pre pass)
-
-		renderPlugins( this.renderPluginsPre, scene, camera );
-
-		//
-
-		_this.info.render.calls = 0;
-		_this.info.render.vertices = 0;
-		_this.info.render.faces = 0;
-		_this.info.render.points = 0;
-
-		this.setRenderTarget( renderTarget );
-
-		if ( this.autoClear || forceClear ) {
-
-			this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
-
-		}
-
-		// set matrices for regular objects (frustum culled)
-
-		renderList = scene.__webglObjects;
-
-		for ( i = 0, il = renderList.length; i < il; i ++ ) {
-
-			webglObject = renderList[ i ];
-			object = webglObject.object;
-
-			webglObject.id = i;
-			webglObject.render = false;
-
-			if ( object.visible ) {
-
-				if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
-
-					setupMatrices( object, camera );
-
-					unrollBufferMaterial( webglObject );
-
-					webglObject.render = true;
-
-					if ( this.sortObjects === true ) {
-
-						if ( object.renderDepth !== null ) {
-
-							webglObject.z = object.renderDepth;
-
-						} else {
-
-							_vector3.getPositionFromMatrix( object.matrixWorld );
-							_vector3.applyProjection( _projScreenMatrix );
-
-							webglObject.z = _vector3.z;
-
-						}
-
-					}
-
-				}
-
-			}
-
-		}
-
-		if ( this.sortObjects ) {
-
-			renderList.sort( painterSortStable );
-
-		}
-
-		// set matrices for immediate objects
-
-		renderList = scene.__webglObjectsImmediate;
-
-		for ( i = 0, il = renderList.length; i < il; i ++ ) {
-
-			webglObject = renderList[ i ];
-			object = webglObject.object;
-
-			if ( object.visible ) {
-
-				setupMatrices( object, camera );
-
-				unrollImmediateBufferMaterial( webglObject );
-
-			}
-
-		}
-
-		if ( scene.overrideMaterial ) {
-
-			var material = scene.overrideMaterial;
-
-			this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
-			this.setDepthTest( material.depthTest );
-			this.setDepthWrite( material.depthWrite );
-			setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
-
-			renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material );
-			renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material );
-
-		} else {
-
-			var material = null;
-
-			// opaque pass (front-to-back order)
-
-			this.setBlending( THREE.NoBlending );
-
-			renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material );
-			renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material );
-
-			// transparent pass (back-to-front order)
-
-			renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material );
-			renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material );
-
-		}
-
-		// custom render plugins (post pass)
-
-		renderPlugins( this.renderPluginsPost, scene, camera );
-
-
-		// Generate mipmap if we're using any kind of mipmap filtering
-
-		if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
-
-			updateRenderTargetMipmap( renderTarget );
-
-		}
-
-		// Ensure depth buffer writing is enabled so it can be cleared on next render
-
-		this.setDepthTest( true );
-		this.setDepthWrite( true );
-
-		// _gl.finish();
-
-	};
-
-	function renderPlugins( plugins, scene, camera ) {
-
-		if ( ! plugins.length ) return;
-
-		for ( var i = 0, il = plugins.length; i < il; i ++ ) {
-
-			// reset state for plugin (to start from clean slate)
-
-			_currentProgram = null;
-			_currentCamera = null;
-
-			_oldBlending = -1;
-			_oldDepthTest = -1;
-			_oldDepthWrite = -1;
-			_oldDoubleSided = -1;
-			_oldFlipSided = -1;
-			_currentGeometryGroupHash = -1;
-			_currentMaterialId = -1;
-
-			_lightsNeedUpdate = true;
-
-			plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );
-
-			// reset state after plugin (anything could have changed)
-
-			_currentProgram = null;
-			_currentCamera = null;
-
-			_oldBlending = -1;
-			_oldDepthTest = -1;
-			_oldDepthWrite = -1;
-			_oldDoubleSided = -1;
-			_oldFlipSided = -1;
-			_currentGeometryGroupHash = -1;
-			_currentMaterialId = -1;
-
-			_lightsNeedUpdate = true;
-
-		}
-
-	};
-
-	function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
-
-		var webglObject, object, buffer, material, start, end, delta;
-
-		if ( reverse ) {
-
-			start = renderList.length - 1;
-			end = -1;
-			delta = -1;
-
-		} else {
-
-			start = 0;
-			end = renderList.length;
-			delta = 1;
-		}
-
-		for ( var i = start; i !== end; i += delta ) {
-
-			webglObject = renderList[ i ];
-
-			if ( webglObject.render ) {
-
-				object = webglObject.object;
-				buffer = webglObject.buffer;
-
-				if ( overrideMaterial ) {
-
-					material = overrideMaterial;
-
-				} else {
-
-					material = webglObject[ materialType ];
-
-					if ( ! material ) continue;
-
-					if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
-
-					_this.setDepthTest( material.depthTest );
-					_this.setDepthWrite( material.depthWrite );
-					setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
-
-				}
-
-				_this.setMaterialFaces( material );
-
-				if ( buffer instanceof THREE.BufferGeometry ) {
-
-					_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
-
-				} else {
-
-					_this.renderBuffer( camera, lights, fog, material, buffer, object );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
-
-		var webglObject, object, material, program;
-
-		for ( var i = 0, il = renderList.length; i < il; i ++ ) {
-
-			webglObject = renderList[ i ];
-			object = webglObject.object;
-
-			if ( object.visible ) {
-
-				if ( overrideMaterial ) {
-
-					material = overrideMaterial;
-
-				} else {
-
-					material = webglObject[ materialType ];
-
-					if ( ! material ) continue;
-
-					if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
-
-					_this.setDepthTest( material.depthTest );
-					_this.setDepthWrite( material.depthWrite );
-					setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
-
-				}
-
-				_this.renderImmediateObject( camera, lights, fog, material, object );
-
-			}
-
-		}
-
-	};
-
-	this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
-
-		var program = setProgram( camera, lights, fog, material, object );
-
-		_currentGeometryGroupHash = -1;
-
-		_this.setMaterialFaces( material );
-
-		if ( object.immediateRenderCallback ) {
-
-			object.immediateRenderCallback( program, _gl, _frustum );
-
-		} else {
-
-			object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );
-
-		}
-
-	};
-
-	function unrollImmediateBufferMaterial ( globject ) {
-
-		var object = globject.object,
-			material = object.material;
-
-		if ( material.transparent ) {
-
-			globject.transparent = material;
-			globject.opaque = null;
-
-		} else {
-
-			globject.opaque = material;
-			globject.transparent = null;
-
-		}
-
-	};
-
-	function unrollBufferMaterial ( globject ) {
-
-		var object = globject.object,
-			buffer = globject.buffer,
-			material, materialIndex, meshMaterial;
-
-		meshMaterial = object.material;
-
-		if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
-
-			materialIndex = buffer.materialIndex;
-
-			material = meshMaterial.materials[ materialIndex ];
-
-			if ( material.transparent ) {
-
-				globject.transparent = material;
-				globject.opaque = null;
-
-			} else {
-
-				globject.opaque = material;
-				globject.transparent = null;
-
-			}
-
-		} else {
-
-			material = meshMaterial;
-
-			if ( material ) {
-
-				if ( material.transparent ) {
-
-					globject.transparent = material;
-					globject.opaque = null;
-
-				} else {
-
-					globject.opaque = material;
-					globject.transparent = null;
-
-				}
-
-			}
-
-		}
-
-	};
-
-	// Geometry splitting
-
-	function sortFacesByMaterial ( geometry, material ) {
-
-		var f, fl, face, materialIndex, vertices,
-			groupHash, hash_map = {};
-
-		var numMorphTargets = geometry.morphTargets.length;
-		var numMorphNormals = geometry.morphNormals.length;
-
-		var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial;
-
-		geometry.geometryGroups = {};
-
-		for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
-
-			face = geometry.faces[ f ];
-			materialIndex = usesFaceMaterial ? face.materialIndex : 0;
-
-			if ( hash_map[ materialIndex ] === undefined ) {
-
-				hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 };
-
-			}
-
-			groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
-
-			if ( geometry.geometryGroups[ groupHash ] === undefined ) {
-
-				geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
-
-			}
-
-			vertices = face instanceof THREE.Face3 ? 3 : 4;
-
-			if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {
-
-				hash_map[ materialIndex ].counter += 1;
-				groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
-
-				if ( geometry.geometryGroups[ groupHash ] === undefined ) {
-
-					geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
-
-				}
-
-			}
-
-			if ( face instanceof THREE.Face3 ) {
-
-				geometry.geometryGroups[ groupHash ].faces3.push( f );
-
-			} else {
-
-				geometry.geometryGroups[ groupHash ].faces4.push( f );
-
-			}
-
-			geometry.geometryGroups[ groupHash ].vertices += vertices;
-
-		}
-
-		geometry.geometryGroupsList = [];
-
-		for ( var g in geometry.geometryGroups ) {
-
-			geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;
-
-			geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );
-
-		}
-
-	};
-
-	// Objects refresh
-
-	this.initWebGLObjects = function ( scene ) {
-
-		if ( !scene.__webglObjects ) {
-
-			scene.__webglObjects = [];
-			scene.__webglObjectsImmediate = [];
-			scene.__webglSprites = [];
-			scene.__webglFlares = [];
-
-		}
-
-		while ( scene.__objectsAdded.length ) {
-
-			addObject( scene.__objectsAdded[ 0 ], scene );
-			scene.__objectsAdded.splice( 0, 1 );
-
-		}
-
-		while ( scene.__objectsRemoved.length ) {
-
-			removeObject( scene.__objectsRemoved[ 0 ], scene );
-			scene.__objectsRemoved.splice( 0, 1 );
-
-		}
-
-		// update must be called after objects adding / removal
-
-		for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
-
-			var object = scene.__webglObjects[ o ].object;
-
-			// TODO: Remove this hack (WebGLRenderer refactoring)
-
-			if ( object.__webglInit === undefined ) {
-
-				if ( object.__webglActive !== undefined ) {
-
-					removeObject( object, scene );
-
-				}
-
-				addObject( object, scene );
-
-			}
-
-			updateObject( object );
-
-		}
-
-	};
-
-	// Objects adding
-
-	function addObject( object, scene ) {
-
-		var g, geometry, material, geometryGroup;
-
-		if ( object.__webglInit === undefined ) {
-
-			object.__webglInit = true;
-
-			object._modelViewMatrix = new THREE.Matrix4();
-			object._normalMatrix = new THREE.Matrix3();
-
-			if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) {
-
-				object.geometry.__webglInit = true;
-				object.geometry.addEventListener( 'dispose', onGeometryDispose );
-
-			}
-
-			geometry = object.geometry;
-
-			if ( geometry === undefined ) {
-
-				// fail silently for now
-
-			} else if ( geometry instanceof THREE.BufferGeometry ) {
-
-				initDirectBuffers( geometry );
-
-			} else if ( object instanceof THREE.Mesh ) {
-
-				material = object.material;
-
-				if ( geometry.geometryGroups === undefined ) {
-
-					sortFacesByMaterial( geometry, material );
-
-				}
-
-				// create separate VBOs per geometry chunk
-
-				for ( g in geometry.geometryGroups ) {
-
-					geometryGroup = geometry.geometryGroups[ g ];
-
-					// initialise VBO on the first access
-
-					if ( ! geometryGroup.__webglVertexBuffer ) {
-
-						createMeshBuffers( geometryGroup );
-						initMeshBuffers( geometryGroup, object );
-
-						geometry.verticesNeedUpdate = true;
-						geometry.morphTargetsNeedUpdate = true;
-						geometry.elementsNeedUpdate = true;
-						geometry.uvsNeedUpdate = true;
-						geometry.normalsNeedUpdate = true;
-						geometry.tangentsNeedUpdate = true;
-						geometry.colorsNeedUpdate = true;
-
-					}
-
-				}
-
-			} else if ( object instanceof THREE.Ribbon ) {
-
-				if ( ! geometry.__webglVertexBuffer ) {
-
-					createRibbonBuffers( geometry );
-					initRibbonBuffers( geometry, object );
-
-					geometry.verticesNeedUpdate = true;
-					geometry.colorsNeedUpdate = true;
-					geometry.normalsNeedUpdate = true;
-
-				}
-
-			} else if ( object instanceof THREE.Line ) {
-
-				if ( ! geometry.__webglVertexBuffer ) {
-
-					createLineBuffers( geometry );
-					initLineBuffers( geometry, object );
-
-					geometry.verticesNeedUpdate = true;
-					geometry.colorsNeedUpdate = true;
-					geometry.lineDistancesNeedUpdate = true;
-
-				}
-
-			} else if ( object instanceof THREE.ParticleSystem ) {
-
-				if ( ! geometry.__webglVertexBuffer ) {
-
-					createParticleBuffers( geometry );
-					initParticleBuffers( geometry, object );
-
-					geometry.verticesNeedUpdate = true;
-					geometry.colorsNeedUpdate = true;
-
-				}
-
-			}
-
-		}
-
-		if ( object.__webglActive === undefined ) {
-
-			if ( object instanceof THREE.Mesh ) {
-
-				geometry = object.geometry;
-
-				if ( geometry instanceof THREE.BufferGeometry ) {
-
-					addBuffer( scene.__webglObjects, geometry, object );
-
-				} else if ( geometry instanceof THREE.Geometry ) {
-
-					for ( g in geometry.geometryGroups ) {
-
-						geometryGroup = geometry.geometryGroups[ g ];
-
-						addBuffer( scene.__webglObjects, geometryGroup, object );
-
-					}
-
-				}
-
-			} else if ( object instanceof THREE.Ribbon ||
-						object instanceof THREE.Line ||
-						object instanceof THREE.ParticleSystem ) {
-
-				geometry = object.geometry;
-				addBuffer( scene.__webglObjects, geometry, object );
-
-			} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
-
-				addBufferImmediate( scene.__webglObjectsImmediate, object );
-
-			} else if ( object instanceof THREE.Sprite ) {
-
-				scene.__webglSprites.push( object );
-
-			} else if ( object instanceof THREE.LensFlare ) {
-
-				scene.__webglFlares.push( object );
-
-			}
-
-			object.__webglActive = true;
-
-		}
-
-	};
-
-	function addBuffer( objlist, buffer, object ) {
-
-		objlist.push(
-			{
-				buffer: buffer,
-				object: object,
-				opaque: null,
-				transparent: null
-			}
-		);
-
-	};
-
-	function addBufferImmediate( objlist, object ) {
-
-		objlist.push(
-			{
-				object: object,
-				opaque: null,
-				transparent: null
-			}
-		);
-
-	};
-
-	// Objects updates
-
-	function updateObject( object ) {
-
-		var geometry = object.geometry,
-			geometryGroup, customAttributesDirty, material;
-
-		if ( geometry instanceof THREE.BufferGeometry ) {
-
-			setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic );
-
-		} else if ( object instanceof THREE.Mesh ) {
-
-			// check all geometry groups
-
-			for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
-
-				geometryGroup = geometry.geometryGroupsList[ i ];
-
-				material = getBufferMaterial( object, geometryGroup );
-
-				if ( geometry.buffersNeedUpdate ) {
-
-					initMeshBuffers( geometryGroup, object );
-
-				}
-
-				customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
-				if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
-					 geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
-					 geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
-
-					setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material );
-
-				}
-
-			}
-
-			geometry.verticesNeedUpdate = false;
-			geometry.morphTargetsNeedUpdate = false;
-			geometry.elementsNeedUpdate = false;
-			geometry.uvsNeedUpdate = false;
-			geometry.normalsNeedUpdate = false;
-			geometry.colorsNeedUpdate = false;
-			geometry.tangentsNeedUpdate = false;
-
-			geometry.buffersNeedUpdate = false;
-
-			material.attributes && clearCustomAttributes( material );
-
-		} else if ( object instanceof THREE.Ribbon ) {
-
-			material = getBufferMaterial( object, geometry );
-
-			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
-			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.normalsNeedUpdate || customAttributesDirty ) {
-
-				setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );
-
-			}
-
-			geometry.verticesNeedUpdate = false;
-			geometry.colorsNeedUpdate = false;
-			geometry.normalsNeedUpdate = false;
-
-			material.attributes && clearCustomAttributes( material );
-
-		} else if ( object instanceof THREE.Line ) {
-
-			material = getBufferMaterial( object, geometry );
-
-			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
-			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
-
-				setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
-
-			}
-
-			geometry.verticesNeedUpdate = false;
-			geometry.colorsNeedUpdate = false;
-			geometry.lineDistancesNeedUpdate = false;
-
-			material.attributes && clearCustomAttributes( material );
-
-
-		} else if ( object instanceof THREE.ParticleSystem ) {
-
-			material = getBufferMaterial( object, geometry );
-
-			customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
-			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) {
-
-				setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
-
-			}
-
-			geometry.verticesNeedUpdate = false;
-			geometry.colorsNeedUpdate = false;
-
-			material.attributes && clearCustomAttributes( material );
-
-		}
-
-	};
-
-	// Objects updates - custom attributes check
-
-	function areCustomAttributesDirty( material ) {
-
-		for ( var a in material.attributes ) {
-
-			if ( material.attributes[ a ].needsUpdate ) return true;
-
-		}
-
-		return false;
-
-	};
-
-	function clearCustomAttributes( material ) {
-
-		for ( var a in material.attributes ) {
-
-			material.attributes[ a ].needsUpdate = false;
-
-		}
-
-	};
-
-	// Objects removal
-
-	function removeObject( object, scene ) {
-
-		if ( object instanceof THREE.Mesh  ||
-			 object instanceof THREE.ParticleSystem ||
-			 object instanceof THREE.Ribbon ||
-			 object instanceof THREE.Line ) {
-
-			removeInstances( scene.__webglObjects, object );
-
-		} else if ( object instanceof THREE.Sprite ) {
-
-			removeInstancesDirect( scene.__webglSprites, object );
-
-		} else if ( object instanceof THREE.LensFlare ) {
-
-			removeInstancesDirect( scene.__webglFlares, object );
-
-		} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
-
-			removeInstances( scene.__webglObjectsImmediate, object );
-
-		}
-
-		delete object.__webglActive;
-
-	};
-
-	function removeInstances( objlist, object ) {
-
-		for ( var o = objlist.length - 1; o >= 0; o -- ) {
-
-			if ( objlist[ o ].object === object ) {
-
-				objlist.splice( o, 1 );
-
-			}
-
-		}
-
-	};
-
-	function removeInstancesDirect( objlist, object ) {
-
-		for ( var o = objlist.length - 1; o >= 0; o -- ) {
-
-			if ( objlist[ o ] === object ) {
-
-				objlist.splice( o, 1 );
-
-			}
-
-		}
-
-	};
-
-	// Materials
-
-	this.initMaterial = function ( material, lights, fog, object ) {
-
-		material.addEventListener( 'dispose', onMaterialDispose );
-
-		var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
-
-		if ( material instanceof THREE.MeshDepthMaterial ) {
-
-			shaderID = 'depth';
-
-		} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-			shaderID = 'normal';
-
-		} else if ( material instanceof THREE.MeshBasicMaterial ) {
-
-			shaderID = 'basic';
-
-		} else if ( material instanceof THREE.MeshLambertMaterial ) {
-
-			shaderID = 'lambert';
-
-		} else if ( material instanceof THREE.MeshPhongMaterial ) {
-
-			shaderID = 'phong';
-
-		} else if ( material instanceof THREE.LineBasicMaterial ) {
-
-			shaderID = 'basic';
-
-		} else if ( material instanceof THREE.LineDashedMaterial ) {
-
-			shaderID = 'dashed';
-
-		} else if ( material instanceof THREE.ParticleBasicMaterial ) {
-
-			shaderID = 'particle_basic';
-
-		}
-
-		if ( shaderID ) {
-
-			setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );
-
-		}
-
-		// heuristics to create shader parameters according to lights in the scene
-		// (not to blow over maxLights budget)
-
-		maxLightCount = allocateLights( lights );
-
-		maxShadows = allocateShadows( lights );
-
-		maxBones = allocateBones( object );
-
-		parameters = {
-
-			map: !!material.map,
-			envMap: !!material.envMap,
-			lightMap: !!material.lightMap,
-			bumpMap: !!material.bumpMap,
-			normalMap: !!material.normalMap,
-			specularMap: !!material.specularMap,
-
-			vertexColors: material.vertexColors,
-
-			fog: fog,
-			useFog: material.fog,
-			fogExp: fog instanceof THREE.FogExp2,
-
-			sizeAttenuation: material.sizeAttenuation,
-
-			skinning: material.skinning,
-			maxBones: maxBones,
-			useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture,
-			boneTextureWidth: object && object.boneTextureWidth,
-			boneTextureHeight: object && object.boneTextureHeight,
-
-			morphTargets: material.morphTargets,
-			morphNormals: material.morphNormals,
-			maxMorphTargets: this.maxMorphTargets,
-			maxMorphNormals: this.maxMorphNormals,
-
-			maxDirLights: maxLightCount.directional,
-			maxPointLights: maxLightCount.point,
-			maxSpotLights: maxLightCount.spot,
-			maxHemiLights: maxLightCount.hemi,
-
-			maxShadows: maxShadows,
-			shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
-			shadowMapType: this.shadowMapType,
-			shadowMapDebug: this.shadowMapDebug,
-			shadowMapCascade: this.shadowMapCascade,
-
-			alphaTest: material.alphaTest,
-			metal: material.metal,
-			perPixel: material.perPixel,
-			wrapAround: material.wrapAround,
-			doubleSided: material.side === THREE.DoubleSide,
-			flipSided: material.side === THREE.BackSide
-
-		};
-
-		material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters );
-
-		var attributes = material.program.attributes;
-
-		if ( material.morphTargets ) {
-
-			material.numSupportedMorphTargets = 0;
-
-			var id, base = "morphTarget";
-
-			for ( i = 0; i < this.maxMorphTargets; i ++ ) {
-
-				id = base + i;
-
-				if ( attributes[ id ] >= 0 ) {
-
-					material.numSupportedMorphTargets ++;
-
-				}
-
-			}
-
-		}
-
-		if ( material.morphNormals ) {
-
-			material.numSupportedMorphNormals = 0;
-
-			var id, base = "morphNormal";
-
-			for ( i = 0; i < this.maxMorphNormals; i ++ ) {
-
-				id = base + i;
-
-				if ( attributes[ id ] >= 0 ) {
-
-					material.numSupportedMorphNormals ++;
-
-				}
-
-			}
-
-		}
-
-		material.uniformsList = [];
-
-		for ( u in material.uniforms ) {
-
-			material.uniformsList.push( [ material.uniforms[ u ], u ] );
-
-		}
-
-	};
-
-	function setMaterialShaders( material, shaders ) {
-
-		material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
-		material.vertexShader = shaders.vertexShader;
-		material.fragmentShader = shaders.fragmentShader;
-
-	};
-
-	function setProgram( camera, lights, fog, material, object ) {
-
-		_usedTextureUnits = 0;
-
-		if ( material.needsUpdate ) {
-
-			if ( material.program ) deallocateMaterial( material );
-
-			_this.initMaterial( material, lights, fog, object );
-			material.needsUpdate = false;
-
-		}
-
-		if ( material.morphTargets ) {
-
-			if ( ! object.__webglMorphTargetInfluences ) {
-
-				object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
-
-			}
-
-		}
-
-		var refreshMaterial = false;
-
-		var program = material.program,
-			p_uniforms = program.uniforms,
-			m_uniforms = material.uniforms;
-
-		if ( program !== _currentProgram ) {
-
-			_gl.useProgram( program );
-			_currentProgram = program;
-
-			refreshMaterial = true;
-
-		}
-
-		if ( material.id !== _currentMaterialId ) {
-
-			_currentMaterialId = material.id;
-			refreshMaterial = true;
-
-		}
-
-		if ( refreshMaterial || camera !== _currentCamera ) {
-
-			_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
-
-			if ( camera !== _currentCamera ) _currentCamera = camera;
-
-		}
-
-		// skinning uniforms must be set even if material didn't change
-		// auto-setting of texture unit for bone texture must go before other textures
-		// not sure why, but otherwise weird things happen
-
-		if ( material.skinning ) {
-
-			if ( _supportsBoneTextures && object.useVertexTexture ) {
-
-				if ( p_uniforms.boneTexture !== null ) {
-
-					var textureUnit = getTextureUnit();
-
-					_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
-					_this.setTexture( object.boneTexture, textureUnit );
-
-				}
-
-			} else {
-
-				if ( p_uniforms.boneGlobalMatrices !== null ) {
-
-					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
-
-				}
-
-			}
-
-		}
-
-		if ( refreshMaterial ) {
-
-			// refresh uniforms common to several materials
-
-			if ( fog && material.fog ) {
-
-				refreshUniformsFog( m_uniforms, fog );
-
-			}
-
-			if ( material instanceof THREE.MeshPhongMaterial ||
-				 material instanceof THREE.MeshLambertMaterial ||
-				 material.lights ) {
-
-				if ( _lightsNeedUpdate ) {
-
-					setupLights( program, lights );
-					_lightsNeedUpdate = false;
-
-				}
-
-				refreshUniformsLights( m_uniforms, _lights );
-
-			}
-
-			if ( material instanceof THREE.MeshBasicMaterial ||
-				 material instanceof THREE.MeshLambertMaterial ||
-				 material instanceof THREE.MeshPhongMaterial ) {
-
-				refreshUniformsCommon( m_uniforms, material );
-
-			}
-
-			// refresh single material specific uniforms
-
-			if ( material instanceof THREE.LineBasicMaterial ) {
-
-				refreshUniformsLine( m_uniforms, material );
-
-			} else if ( material instanceof THREE.LineDashedMaterial ) {
-
-				refreshUniformsLine( m_uniforms, material );
-				refreshUniformsDash( m_uniforms, material );
-
-			} else if ( material instanceof THREE.ParticleBasicMaterial ) {
-
-				refreshUniformsParticle( m_uniforms, material );
-
-			} else if ( material instanceof THREE.MeshPhongMaterial ) {
-
-				refreshUniformsPhong( m_uniforms, material );
-
-			} else if ( material instanceof THREE.MeshLambertMaterial ) {
-
-				refreshUniformsLambert( m_uniforms, material );
-
-			} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-				m_uniforms.mNear.value = camera.near;
-				m_uniforms.mFar.value = camera.far;
-				m_uniforms.opacity.value = material.opacity;
-
-			} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-				m_uniforms.opacity.value = material.opacity;
-
-			}
-
-			if ( object.receiveShadow && ! material._shadowPass ) {
-
-				refreshUniformsShadow( m_uniforms, lights );
-
-			}
-
-			// load common uniforms
-
-			loadUniformsGeneric( program, material.uniformsList );
-
-			// load material specific uniforms
-			// (shader material also gets them for the sake of genericity)
-
-			if ( material instanceof THREE.ShaderMaterial ||
-				 material instanceof THREE.MeshPhongMaterial ||
-				 material.envMap ) {
-
-				if ( p_uniforms.cameraPosition !== null ) {
-
-					_vector3.getPositionFromMatrix( camera.matrixWorld );
-					_gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );
-
-				}
-
-			}
-
-			if ( material instanceof THREE.MeshPhongMaterial ||
-				 material instanceof THREE.MeshLambertMaterial ||
-				 material instanceof THREE.ShaderMaterial ||
-				 material.skinning ) {
-
-				if ( p_uniforms.viewMatrix !== null ) {
-
-					_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );
-
-				}
-
-			}
-
-		}
-
-		loadUniformsMatrices( p_uniforms, object );
-
-		if ( p_uniforms.modelMatrix !== null ) {
-
-			_gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );
-
-		}
-
-		return program;
-
-	};
-
-	// Uniforms (refresh uniforms objects)
-
-	function refreshUniformsCommon ( uniforms, material ) {
-
-		uniforms.opacity.value = material.opacity;
-
-		if ( _this.gammaInput ) {
-
-			uniforms.diffuse.value.copyGammaToLinear( material.color );
-
-		} else {
-
-			uniforms.diffuse.value = material.color;
-
-		}
-
-		uniforms.map.value = material.map;
-		uniforms.lightMap.value = material.lightMap;
-		uniforms.specularMap.value = material.specularMap;
-
-		if ( material.bumpMap ) {
-
-			uniforms.bumpMap.value = material.bumpMap;
-			uniforms.bumpScale.value = material.bumpScale;
-
-		}
-
-		if ( material.normalMap ) {
-
-			uniforms.normalMap.value = material.normalMap;
-			uniforms.normalScale.value.copy( material.normalScale );
-
-		}
-
-		// uv repeat and offset setting priorities
-		//	1. color map
-		//	2. specular map
-		//	3. normal map
-		//	4. bump map
-
-		var uvScaleMap;
-
-		if ( material.map ) {
-
-			uvScaleMap = material.map;
-
-		} else if ( material.specularMap ) {
-
-			uvScaleMap = material.specularMap;
-
-		} else if ( material.normalMap ) {
-
-			uvScaleMap = material.normalMap;
-
-		} else if ( material.bumpMap ) {
-
-			uvScaleMap = material.bumpMap;
-
-		}
-
-		if ( uvScaleMap !== undefined ) {
-
-			var offset = uvScaleMap.offset;
-			var repeat = uvScaleMap.repeat;
-
-			uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
-
-		}
-
-		uniforms.envMap.value = material.envMap;
-		uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
-
-		if ( _this.gammaInput ) {
-
-			//uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
-			uniforms.reflectivity.value = material.reflectivity;
-
-		} else {
-
-			uniforms.reflectivity.value = material.reflectivity;
-
-		}
-
-		uniforms.refractionRatio.value = material.refractionRatio;
-		uniforms.combine.value = material.combine;
-		uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
-
-	};
-
-	function refreshUniformsLine ( uniforms, material ) {
-
-		uniforms.diffuse.value = material.color;
-		uniforms.opacity.value = material.opacity;
-
-	};
-
-	function refreshUniformsDash ( uniforms, material ) {
-
-		uniforms.dashSize.value = material.dashSize;
-		uniforms.totalSize.value = material.dashSize + material.gapSize;
-		uniforms.scale.value = material.scale;
-
-	};
-
-	function refreshUniformsParticle ( uniforms, material ) {
-
-		uniforms.psColor.value = material.color;
-		uniforms.opacity.value = material.opacity;
-		uniforms.size.value = material.size;
-		uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.
-
-		uniforms.map.value = material.map;
-
-	};
-
-	function refreshUniformsFog ( uniforms, fog ) {
-
-		uniforms.fogColor.value = fog.color;
-
-		if ( fog instanceof THREE.Fog ) {
-
-			uniforms.fogNear.value = fog.near;
-			uniforms.fogFar.value = fog.far;
-
-		} else if ( fog instanceof THREE.FogExp2 ) {
-
-			uniforms.fogDensity.value = fog.density;
-
-		}
-
-	};
-
-	function refreshUniformsPhong ( uniforms, material ) {
-
-		uniforms.shininess.value = material.shininess;
-
-		if ( _this.gammaInput ) {
-
-			uniforms.ambient.value.copyGammaToLinear( material.ambient );
-			uniforms.emissive.value.copyGammaToLinear( material.emissive );
-			uniforms.specular.value.copyGammaToLinear( material.specular );
-
-		} else {
-
-			uniforms.ambient.value = material.ambient;
-			uniforms.emissive.value = material.emissive;
-			uniforms.specular.value = material.specular;
-
-		}
-
-		if ( material.wrapAround ) {
-
-			uniforms.wrapRGB.value.copy( material.wrapRGB );
-
-		}
-
-	};
-
-	function refreshUniformsLambert ( uniforms, material ) {
-
-		if ( _this.gammaInput ) {
-
-			uniforms.ambient.value.copyGammaToLinear( material.ambient );
-			uniforms.emissive.value.copyGammaToLinear( material.emissive );
-
-		} else {
-
-			uniforms.ambient.value = material.ambient;
-			uniforms.emissive.value = material.emissive;
-
-		}
-
-		if ( material.wrapAround ) {
-
-			uniforms.wrapRGB.value.copy( material.wrapRGB );
-
-		}
-
-	};
-
-	function refreshUniformsLights ( uniforms, lights ) {
-
-		uniforms.ambientLightColor.value = lights.ambient;
-
-		uniforms.directionalLightColor.value = lights.directional.colors;
-		uniforms.directionalLightDirection.value = lights.directional.positions;
-
-		uniforms.pointLightColor.value = lights.point.colors;
-		uniforms.pointLightPosition.value = lights.point.positions;
-		uniforms.pointLightDistance.value = lights.point.distances;
-
-		uniforms.spotLightColor.value = lights.spot.colors;
-		uniforms.spotLightPosition.value = lights.spot.positions;
-		uniforms.spotLightDistance.value = lights.spot.distances;
-		uniforms.spotLightDirection.value = lights.spot.directions;
-		uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
-		uniforms.spotLightExponent.value = lights.spot.exponents;
-
-		uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
-		uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
-		uniforms.hemisphereLightDirection.value = lights.hemi.positions;
-
-	};
-
-	function refreshUniformsShadow ( uniforms, lights ) {
-
-		if ( uniforms.shadowMatrix ) {
-
-			var j = 0;
-
-			for ( var i = 0, il = lights.length; i < il; i ++ ) {
-
-				var light = lights[ i ];
-
-				if ( ! light.castShadow ) continue;
-
-				if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
-
-					uniforms.shadowMap.value[ j ] = light.shadowMap;
-					uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
-
-					uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
-
-					uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
-					uniforms.shadowBias.value[ j ] = light.shadowBias;
-
-					j ++;
-
-				}
-
-			}
-
-		}
-
-	};
-
-	// Uniforms (load to GPU)
-
-	function loadUniformsMatrices ( uniforms, object ) {
-
-		_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );
-
-		if ( uniforms.normalMatrix ) {
-
-			_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );
-
-		}
-
-	};
-
-	function getTextureUnit() {
-
-		var textureUnit = _usedTextureUnits;
-
-		if ( textureUnit >= _maxTextures ) {
-
-			console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures );
-
-		}
-
-		_usedTextureUnits += 1;
-
-		return textureUnit;
-
-	};
-
-	function loadUniformsGeneric ( program, uniforms ) {
-
-		var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;
-
-		for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {
-
-			location = program.uniforms[ uniforms[ j ][ 1 ] ];
-			if ( !location ) continue;
-
-			uniform = uniforms[ j ][ 0 ];
-
-			type = uniform.type;
-			value = uniform.value;
-
-			if ( type === "i" ) { // single integer
-
-				_gl.uniform1i( location, value );
-
-			} else if ( type === "f" ) { // single float
-
-				_gl.uniform1f( location, value );
-
-			} else if ( type === "v2" ) { // single THREE.Vector2
-
-				_gl.uniform2f( location, value.x, value.y );
-
-			} else if ( type === "v3" ) { // single THREE.Vector3
-
-				_gl.uniform3f( location, value.x, value.y, value.z );
-
-			} else if ( type === "v4" ) { // single THREE.Vector4
-
-				_gl.uniform4f( location, value.x, value.y, value.z, value.w );
-
-			} else if ( type === "c" ) { // single THREE.Color
-
-				_gl.uniform3f( location, value.r, value.g, value.b );
-
-			} else if ( type === "iv1" ) { // flat array of integers (JS or typed array)
-
-				_gl.uniform1iv( location, value );
-
-			} else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array)
-
-				_gl.uniform3iv( location, value );
-
-			} else if ( type === "fv1" ) { // flat array of floats (JS or typed array)
-
-				_gl.uniform1fv( location, value );
-
-			} else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array)
-
-				_gl.uniform3fv( location, value );
-
-			} else if ( type === "v2v" ) { // array of THREE.Vector2
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = new Float32Array( 2 * value.length );
-
-				}
-
-				for ( i = 0, il = value.length; i < il; i ++ ) {
-
-					offset = i * 2;
-
-					uniform._array[ offset ] 	 = value[ i ].x;
-					uniform._array[ offset + 1 ] = value[ i ].y;
-
-				}
-
-				_gl.uniform2fv( location, uniform._array );
-
-			} else if ( type === "v3v" ) { // array of THREE.Vector3
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = new Float32Array( 3 * value.length );
-
-				}
-
-				for ( i = 0, il = value.length; i < il; i ++ ) {
-
-					offset = i * 3;
-
-					uniform._array[ offset ] 	 = value[ i ].x;
-					uniform._array[ offset + 1 ] = value[ i ].y;
-					uniform._array[ offset + 2 ] = value[ i ].z;
-
-				}
-
-				_gl.uniform3fv( location, uniform._array );
-
-			} else if ( type === "v4v" ) { // array of THREE.Vector4
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = new Float32Array( 4 * value.length );
-
-				}
-
-				for ( i = 0, il = value.length; i < il; i ++ ) {
-
-					offset = i * 4;
-
-					uniform._array[ offset ] 	 = value[ i ].x;
-					uniform._array[ offset + 1 ] = value[ i ].y;
-					uniform._array[ offset + 2 ] = value[ i ].z;
-					uniform._array[ offset + 3 ] = value[ i ].w;
-
-				}
-
-				_gl.uniform4fv( location, uniform._array );
-
-			} else if ( type === "m4") { // single THREE.Matrix4
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = new Float32Array( 16 );
-
-				}
-
-				value.flattenToArray( uniform._array );
-				_gl.uniformMatrix4fv( location, false, uniform._array );
-
-			} else if ( type === "m4v" ) { // array of THREE.Matrix4
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = new Float32Array( 16 * value.length );
-
-				}
-
-				for ( i = 0, il = value.length; i < il; i ++ ) {
-
-					value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
-
-				}
-
-				_gl.uniformMatrix4fv( location, false, uniform._array );
-
-			} else if ( type === "t" ) { // single THREE.Texture (2d or cube)
-
-				texture = value;
-				textureUnit = getTextureUnit();
-
-				_gl.uniform1i( location, textureUnit );
-
-				if ( !texture ) continue;
-
-				if ( texture.image instanceof Array && texture.image.length === 6 ) {
-
-					setCubeTexture( texture, textureUnit );
-
-				} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
-
-					setCubeTextureDynamic( texture, textureUnit );
-
-				} else {
-
-					_this.setTexture( texture, textureUnit );
-
-				}
-
-			} else if ( type === "tv" ) { // array of THREE.Texture (2d)
-
-				if ( uniform._array === undefined ) {
-
-					uniform._array = [];
-
-				}
-
-				for( i = 0, il = uniform.value.length; i < il; i ++ ) {
-
-					uniform._array[ i ] = getTextureUnit();
-
-				}
-
-				_gl.uniform1iv( location, uniform._array );
-
-				for( i = 0, il = uniform.value.length; i < il; i ++ ) {
-
-					texture = uniform.value[ i ];
-					textureUnit = uniform._array[ i ];
-
-					if ( !texture ) continue;
-
-					_this.setTexture( texture, textureUnit );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function setupMatrices ( object, camera ) {
-
-		object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
-		object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
-
-	};
-
-	//
-
-	function setColorGamma( array, offset, color, intensitySq ) {
-
-		array[ offset ]     = color.r * color.r * intensitySq;
-		array[ offset + 1 ] = color.g * color.g * intensitySq;
-		array[ offset + 2 ] = color.b * color.b * intensitySq;
-
-	};
-
-	function setColorLinear( array, offset, color, intensity ) {
-
-		array[ offset ]     = color.r * intensity;
-		array[ offset + 1 ] = color.g * intensity;
-		array[ offset + 2 ] = color.b * intensity;
-
-	};
-
-	function setupLights ( program, lights ) {
-
-		var l, ll, light, n,
-		r = 0, g = 0, b = 0,
-		color, skyColor, groundColor,
-		intensity,  intensitySq,
-		position,
-		distance,
-
-		zlights = _lights,
-
-		dirColors = zlights.directional.colors,
-		dirPositions = zlights.directional.positions,
-
-		pointColors = zlights.point.colors,
-		pointPositions = zlights.point.positions,
-		pointDistances = zlights.point.distances,
-
-		spotColors = zlights.spot.colors,
-		spotPositions = zlights.spot.positions,
-		spotDistances = zlights.spot.distances,
-		spotDirections = zlights.spot.directions,
-		spotAnglesCos = zlights.spot.anglesCos,
-		spotExponents = zlights.spot.exponents,
-
-		hemiSkyColors = zlights.hemi.skyColors,
-		hemiGroundColors = zlights.hemi.groundColors,
-		hemiPositions = zlights.hemi.positions,
-
-		dirLength = 0,
-		pointLength = 0,
-		spotLength = 0,
-		hemiLength = 0,
-
-		dirCount = 0,
-		pointCount = 0,
-		spotCount = 0,
-		hemiCount = 0,
-
-		dirOffset = 0,
-		pointOffset = 0,
-		spotOffset = 0,
-		hemiOffset = 0;
-
-		for ( l = 0, ll = lights.length; l < ll; l ++ ) {
-
-			light = lights[ l ];
-
-			if ( light.onlyShadow ) continue;
-
-			color = light.color;
-			intensity = light.intensity;
-			distance = light.distance;
-
-			if ( light instanceof THREE.AmbientLight ) {
-
-				if ( ! light.visible ) continue;
-
-				if ( _this.gammaInput ) {
-
-					r += color.r * color.r;
-					g += color.g * color.g;
-					b += color.b * color.b;
-
-				} else {
-
-					r += color.r;
-					g += color.g;
-					b += color.b;
-
-				}
-
-			} else if ( light instanceof THREE.DirectionalLight ) {
-
-				dirCount += 1;
-
-				if ( ! light.visible ) continue;
-
-				_direction.getPositionFromMatrix( light.matrixWorld );
-				_vector3.getPositionFromMatrix( light.target.matrixWorld );
-				_direction.sub( _vector3 );
-				_direction.normalize();
-
-				// skip lights with undefined direction
-				// these create troubles in OpenGL (making pixel black)
-
-				if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
-
-				dirOffset = dirLength * 3;
-
-				dirPositions[ dirOffset ]     = _direction.x;
-				dirPositions[ dirOffset + 1 ] = _direction.y;
-				dirPositions[ dirOffset + 2 ] = _direction.z;
-
-				if ( _this.gammaInput ) {
-
-					setColorGamma( dirColors, dirOffset, color, intensity * intensity );
-
-				} else {
-
-					setColorLinear( dirColors, dirOffset, color, intensity );
-
-				}
-
-				dirLength += 1;
-
-			} else if ( light instanceof THREE.PointLight ) {
-
-				pointCount += 1;
-
-				if ( ! light.visible ) continue;
-
-				pointOffset = pointLength * 3;
-
-				if ( _this.gammaInput ) {
-
-					setColorGamma( pointColors, pointOffset, color, intensity * intensity );
-
-				} else {
-
-					setColorLinear( pointColors, pointOffset, color, intensity );
-
-				}
-
-				_vector3.getPositionFromMatrix( light.matrixWorld );
-
-				pointPositions[ pointOffset ]     = _vector3.x;
-				pointPositions[ pointOffset + 1 ] = _vector3.y;
-				pointPositions[ pointOffset + 2 ] = _vector3.z;
-
-				pointDistances[ pointLength ] = distance;
-
-				pointLength += 1;
-
-			} else if ( light instanceof THREE.SpotLight ) {
-
-				spotCount += 1;
-
-				if ( ! light.visible ) continue;
-
-				spotOffset = spotLength * 3;
-
-				if ( _this.gammaInput ) {
-
-					setColorGamma( spotColors, spotOffset, color, intensity * intensity );
-
-				} else {
-
-					setColorLinear( spotColors, spotOffset, color, intensity );
-
-				}
-
-				_vector3.getPositionFromMatrix( light.matrixWorld );
-
-				spotPositions[ spotOffset ]     = _vector3.x;
-				spotPositions[ spotOffset + 1 ] = _vector3.y;
-				spotPositions[ spotOffset + 2 ] = _vector3.z;
-
-				spotDistances[ spotLength ] = distance;
-
-				_direction.copy( _vector3 );
-				_vector3.getPositionFromMatrix( light.target.matrixWorld );
-				_direction.sub( _vector3 );
-				_direction.normalize();
-
-				spotDirections[ spotOffset ]     = _direction.x;
-				spotDirections[ spotOffset + 1 ] = _direction.y;
-				spotDirections[ spotOffset + 2 ] = _direction.z;
-
-				spotAnglesCos[ spotLength ] = Math.cos( light.angle );
-				spotExponents[ spotLength ] = light.exponent;
-
-				spotLength += 1;
-
-			} else if ( light instanceof THREE.HemisphereLight ) {
-
-				hemiCount += 1;
-
-				if ( ! light.visible ) continue;
-
-				_direction.getPositionFromMatrix( light.matrixWorld );
-				_direction.normalize();
-
-				// skip lights with undefined direction
-				// these create troubles in OpenGL (making pixel black)
-
-				if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
-
-				hemiOffset = hemiLength * 3;
-
-				hemiPositions[ hemiOffset ]     = _direction.x;
-				hemiPositions[ hemiOffset + 1 ] = _direction.y;
-				hemiPositions[ hemiOffset + 2 ] = _direction.z;
-
-				skyColor = light.color;
-				groundColor = light.groundColor;
-
-				if ( _this.gammaInput ) {
-
-					intensitySq = intensity * intensity;
-
-					setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq );
-					setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq );
-
-				} else {
-
-					setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
-					setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
-
-				}
-
-				hemiLength += 1;
-
-			}
-
-		}
-
-		// null eventual remains from removed lights
-		// (this is to avoid if in shader)
-
-		for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
-		for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
-		for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
-		for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
-		for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
-
-		zlights.directional.length = dirLength;
-		zlights.point.length = pointLength;
-		zlights.spot.length = spotLength;
-		zlights.hemi.length = hemiLength;
-
-		zlights.ambient[ 0 ] = r;
-		zlights.ambient[ 1 ] = g;
-		zlights.ambient[ 2 ] = b;
-
-	};
-
-	// GL state setting
-
-	this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
-
-		if ( cullFace === THREE.CullFaceNone ) {
-
-			_gl.disable( _gl.CULL_FACE );
-
-		} else {
-
-			if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
-
-				_gl.frontFace( _gl.CW );
-
-			} else {
-
-				_gl.frontFace( _gl.CCW );
-
-			}
-
-			if ( cullFace === THREE.CullFaceBack ) {
-
-				_gl.cullFace( _gl.BACK );
-
-			} else if ( cullFace === THREE.CullFaceFront ) {
-
-				_gl.cullFace( _gl.FRONT );
-
-			} else {
-
-				_gl.cullFace( _gl.FRONT_AND_BACK );
-
-			}
-
-			_gl.enable( _gl.CULL_FACE );
-
-		}
-
-	};
-
-	this.setMaterialFaces = function ( material ) {
-
-		var doubleSided = material.side === THREE.DoubleSide;
-		var flipSided = material.side === THREE.BackSide;
-
-		if ( _oldDoubleSided !== doubleSided ) {
-
-			if ( doubleSided ) {
-
-				_gl.disable( _gl.CULL_FACE );
-
-			} else {
-
-				_gl.enable( _gl.CULL_FACE );
-
-			}
-
-			_oldDoubleSided = doubleSided;
-
-		}
-
-		if ( _oldFlipSided !== flipSided ) {
-
-			if ( flipSided ) {
-
-				_gl.frontFace( _gl.CW );
-
-			} else {
-
-				_gl.frontFace( _gl.CCW );
-
-			}
-
-			_oldFlipSided = flipSided;
-
-		}
-
-	};
-
-	this.setDepthTest = function ( depthTest ) {
-
-		if ( _oldDepthTest !== depthTest ) {
-
-			if ( depthTest ) {
-
-				_gl.enable( _gl.DEPTH_TEST );
-
-			} else {
-
-				_gl.disable( _gl.DEPTH_TEST );
-
-			}
-
-			_oldDepthTest = depthTest;
-
-		}
-
-	};
-
-	this.setDepthWrite = function ( depthWrite ) {
-
-		if ( _oldDepthWrite !== depthWrite ) {
-
-			_gl.depthMask( depthWrite );
-			_oldDepthWrite = depthWrite;
-
-		}
-
-	};
-
-	function setLineWidth ( width ) {
-
-		if ( width !== _oldLineWidth ) {
-
-			_gl.lineWidth( width );
-
-			_oldLineWidth = width;
-
-		}
-
-	};
-
-	function setPolygonOffset ( polygonoffset, factor, units ) {
-
-		if ( _oldPolygonOffset !== polygonoffset ) {
-
-			if ( polygonoffset ) {
-
-				_gl.enable( _gl.POLYGON_OFFSET_FILL );
-
-			} else {
-
-				_gl.disable( _gl.POLYGON_OFFSET_FILL );
-
-			}
-
-			_oldPolygonOffset = polygonoffset;
-
-		}
-
-		if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
-
-			_gl.polygonOffset( factor, units );
-
-			_oldPolygonOffsetFactor = factor;
-			_oldPolygonOffsetUnits = units;
-
-		}
-
-	};
-
-	this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) {
-
-		if ( blending !== _oldBlending ) {
-
-			if ( blending === THREE.NoBlending ) {
-
-				_gl.disable( _gl.BLEND );
-
-			} else if ( blending === THREE.AdditiveBlending ) {
-
-				_gl.enable( _gl.BLEND );
-				_gl.blendEquation( _gl.FUNC_ADD );
-				_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
-
-			} else if ( blending === THREE.SubtractiveBlending ) {
-
-				// TODO: Find blendFuncSeparate() combination
-				_gl.enable( _gl.BLEND );
-				_gl.blendEquation( _gl.FUNC_ADD );
-				_gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
-
-			} else if ( blending === THREE.MultiplyBlending ) {
-
-				// TODO: Find blendFuncSeparate() combination
-				_gl.enable( _gl.BLEND );
-				_gl.blendEquation( _gl.FUNC_ADD );
-				_gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
-
-			} else if ( blending === THREE.CustomBlending ) {
-
-				_gl.enable( _gl.BLEND );
-
-			} else {
-
-				_gl.enable( _gl.BLEND );
-				_gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
-				_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
-
-			}
-
-			_oldBlending = blending;
-
-		}
-
-		if ( blending === THREE.CustomBlending ) {
-
-			if ( blendEquation !== _oldBlendEquation ) {
-
-				_gl.blendEquation( paramThreeToGL( blendEquation ) );
-
-				_oldBlendEquation = blendEquation;
-
-			}
-
-			if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {
-
-				_gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );
-
-				_oldBlendSrc = blendSrc;
-				_oldBlendDst = blendDst;
-
-			}
-
-		} else {
-
-			_oldBlendEquation = null;
-			_oldBlendSrc = null;
-			_oldBlendDst = null;
-
-		}
-
-	};
-
-	// Defines
-
-	function generateDefines ( defines ) {
-
-		var value, chunk, chunks = [];
-
-		for ( var d in defines ) {
-
-			value = defines[ d ];
-			if ( value === false ) continue;
-
-			chunk = "#define " + d + " " + value;
-			chunks.push( chunk );
-
-		}
-
-		return chunks.join( "\n" );
-
-	};
-
-	// Shaders
-
-	function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters ) {
-
-		var p, pl, d, program, code;
-		var chunks = [];
-
-		// Generate code
-
-		if ( shaderID ) {
-
-			chunks.push( shaderID );
-
-		} else {
-
-			chunks.push( fragmentShader );
-			chunks.push( vertexShader );
-
-		}
-
-		for ( d in defines ) {
-
-			chunks.push( d );
-			chunks.push( defines[ d ] );
-
-		}
-
-		for ( p in parameters ) {
-
-			chunks.push( p );
-			chunks.push( parameters[ p ] );
-
-		}
-
-		code = chunks.join();
-
-		// Check if code has been already compiled
-
-		for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
-
-			var programInfo = _programs[ p ];
-
-			if ( programInfo.code === code ) {
-
-				// console.log( "Code already compiled." /*: \n\n" + code*/ );
-
-				programInfo.usedTimes ++;
-
-				return programInfo.program;
-
-			}
-
-		}
-
-		var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
-
-		if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
-
-			shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
-
-		} else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
-
-			shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
-
-		}
-
-		// console.log( "building new program " );
-
-		//
-
-		var customDefines = generateDefines( defines );
-
-		//
-
-		program = _gl.createProgram();
-
-		var prefix_vertex = [
-
-			"precision " + _precision + " float;",
-
-			customDefines,
-
-			_supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
-
-			_this.gammaInput ? "#define GAMMA_INPUT" : "",
-			_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
-			_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
-
-			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
-			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
-			"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
-			"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
-
-			"#define MAX_SHADOWS " + parameters.maxShadows,
-
-			"#define MAX_BONES " + parameters.maxBones,
-
-			parameters.map ? "#define USE_MAP" : "",
-			parameters.envMap ? "#define USE_ENVMAP" : "",
-			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
-			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
-			parameters.normalMap ? "#define USE_NORMALMAP" : "",
-			parameters.specularMap ? "#define USE_SPECULARMAP" : "",
-			parameters.vertexColors ? "#define USE_COLOR" : "",
-
-			parameters.skinning ? "#define USE_SKINNING" : "",
-			parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
-			parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "",
-			parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "",
-
-			parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
-			parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
-			parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
-			parameters.wrapAround ? "#define WRAP_AROUND" : "",
-			parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
-			parameters.flipSided ? "#define FLIP_SIDED" : "",
-
-			parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
-			parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
-			parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
-			parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
-
-			parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
-
-			"uniform mat4 modelMatrix;",
-			"uniform mat4 modelViewMatrix;",
-			"uniform mat4 projectionMatrix;",
-			"uniform mat4 viewMatrix;",
-			"uniform mat3 normalMatrix;",
-			"uniform vec3 cameraPosition;",
-
-			"attribute vec3 position;",
-			"attribute vec3 normal;",
-			"attribute vec2 uv;",
-			"attribute vec2 uv2;",
-
-			"#ifdef USE_COLOR",
-
-				"attribute vec3 color;",
-
-			"#endif",
-
-			"#ifdef USE_MORPHTARGETS",
-
-				"attribute vec3 morphTarget0;",
-				"attribute vec3 morphTarget1;",
-				"attribute vec3 morphTarget2;",
-				"attribute vec3 morphTarget3;",
-
-				"#ifdef USE_MORPHNORMALS",
-
-					"attribute vec3 morphNormal0;",
-					"attribute vec3 morphNormal1;",
-					"attribute vec3 morphNormal2;",
-					"attribute vec3 morphNormal3;",
-
-				"#else",
-
-					"attribute vec3 morphTarget4;",
-					"attribute vec3 morphTarget5;",
-					"attribute vec3 morphTarget6;",
-					"attribute vec3 morphTarget7;",
-
-				"#endif",
-
-			"#endif",
-
-			"#ifdef USE_SKINNING",
-
-				"attribute vec4 skinIndex;",
-				"attribute vec4 skinWeight;",
-
-			"#endif",
-
-			""
-
-		].join("\n");
-
-		var prefix_fragment = [
-
-			"precision " + _precision + " float;",
-
-			( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
-
-			customDefines,
-
-			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
-			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
-			"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
-			"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
-
-			"#define MAX_SHADOWS " + parameters.maxShadows,
-
-			parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
-
-			_this.gammaInput ? "#define GAMMA_INPUT" : "",
-			_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
-			_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
-
-			( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
-			( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
-
-			parameters.map ? "#define USE_MAP" : "",
-			parameters.envMap ? "#define USE_ENVMAP" : "",
-			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
-			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
-			parameters.normalMap ? "#define USE_NORMALMAP" : "",
-			parameters.specularMap ? "#define USE_SPECULARMAP" : "",
-			parameters.vertexColors ? "#define USE_COLOR" : "",
-
-			parameters.metal ? "#define METAL" : "",
-			parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
-			parameters.wrapAround ? "#define WRAP_AROUND" : "",
-			parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
-			parameters.flipSided ? "#define FLIP_SIDED" : "",
-
-			parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
-			parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
-			parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
-			parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
-
-			"uniform mat4 viewMatrix;",
-			"uniform vec3 cameraPosition;",
-			""
-
-		].join("\n");
-
-		var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
-		var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
-
-		_gl.attachShader( program, glVertexShader );
-		_gl.attachShader( program, glFragmentShader );
-
-		_gl.linkProgram( program );
-
-		if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
-
-			console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
-
-		}
-
-		// clean up
-
-		_gl.deleteShader( glFragmentShader );
-		_gl.deleteShader( glVertexShader );
-
-		// console.log( prefix_fragment + fragmentShader );
-		// console.log( prefix_vertex + vertexShader );
-
-		program.uniforms = {};
-		program.attributes = {};
-
-		var identifiers, u, a, i;
-
-		// cache uniform locations
-
-		identifiers = [
-
-			'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
-			'morphTargetInfluences'
-
-		];
-
-		if ( parameters.useVertexTexture ) {
-
-			identifiers.push( 'boneTexture' );
-
-		} else {
-
-			identifiers.push( 'boneGlobalMatrices' );
-
-		}
-
-		for ( u in uniforms ) {
-
-			identifiers.push( u );
-
-		}
-
-		cacheUniformLocations( program, identifiers );
-
-		// cache attributes locations
-
-		identifiers = [
-
-			"position", "normal", "uv", "uv2", "tangent", "color",
-			"skinIndex", "skinWeight", "lineDistance"
-
-		];
-
-		for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
-
-			identifiers.push( "morphTarget" + i );
-
-		}
-
-		for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
-
-			identifiers.push( "morphNormal" + i );
-
-		}
-
-		for ( a in attributes ) {
-
-			identifiers.push( a );
-
-		}
-
-		cacheAttributeLocations( program, identifiers );
-
-		program.id = _programs_counter ++;
-
-		_programs.push( { program: program, code: code, usedTimes: 1 } );
-
-		_this.info.memory.programs = _programs.length;
-
-		return program;
-
-	};
-
-	// Shader parameters cache
-
-	function cacheUniformLocations ( program, identifiers ) {
-
-		var i, l, id;
-
-		for( i = 0, l = identifiers.length; i < l; i ++ ) {
-
-			id = identifiers[ i ];
-			program.uniforms[ id ] = _gl.getUniformLocation( program, id );
-
-		}
-
-	};
-
-	function cacheAttributeLocations ( program, identifiers ) {
-
-		var i, l, id;
-
-		for( i = 0, l = identifiers.length; i < l; i ++ ) {
-
-			id = identifiers[ i ];
-			program.attributes[ id ] = _gl.getAttribLocation( program, id );
-
-		}
-
-	};
-
-	function addLineNumbers ( string ) {
-
-		var chunks = string.split( "\n" );
-
-		for ( var i = 0, il = chunks.length; i < il; i ++ ) {
-
-			// Chrome reports shader errors on lines
-			// starting counting from 1
-
-			chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];
-
-		}
-
-		return chunks.join( "\n" );
-
-	};
-
-	function getShader ( type, string ) {
-
-		var shader;
-
-		if ( type === "fragment" ) {
-
-			shader = _gl.createShader( _gl.FRAGMENT_SHADER );
-
-		} else if ( type === "vertex" ) {
-
-			shader = _gl.createShader( _gl.VERTEX_SHADER );
-
-		}
-
-		_gl.shaderSource( shader, string );
-		_gl.compileShader( shader );
-
-		if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
-
-			console.error( _gl.getShaderInfoLog( shader ) );
-			console.error( addLineNumbers( string ) );
-			return null;
-
-		}
-
-		return shader;
-
-	};
-
-	// Textures
-
-
-	function isPowerOfTwo ( value ) {
-
-		return ( value & ( value - 1 ) ) === 0;
-
-	};
-
-	function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
-
-		if ( isImagePowerOfTwo ) {
-
-			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
-			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
-
-			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
-			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
-
-		} else {
-
-			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
-			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
-
-			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
-			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
-
-		}
-
-		if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
-
-			if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
-
-				_gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
-				texture.__oldAnisotropy = texture.anisotropy;
-
-			}
-
-		}
-
-	};
-
-	this.setTexture = function ( texture, slot ) {
-
-		if ( texture.needsUpdate ) {
-
-			if ( ! texture.__webglInit ) {
-
-				texture.__webglInit = true;
-
-				texture.addEventListener( 'dispose', onTextureDispose );
-
-				texture.__webglTexture = _gl.createTexture();
-
-				_this.info.memory.textures ++;
-
-			}
-
-			_gl.activeTexture( _gl.TEXTURE0 + slot );
-			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-
-			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
-			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
-			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
-
-			var image = texture.image,
-			isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
-			glFormat = paramThreeToGL( texture.format ),
-			glType = paramThreeToGL( texture.type );
-
-			setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
-
-			var mipmap, mipmaps = texture.mipmaps;
-
-			if ( texture instanceof THREE.DataTexture ) {
-
-				// use manually created mipmaps if available
-				// if there are no manual mipmaps
-				// set 0 level mipmap and then use GL to generate other mipmap levels
-
-				if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
-
-					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
-						mipmap = mipmaps[ i ];
-						_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
-
-					}
-
-					texture.generateMipmaps = false;
-
-				} else {
-
-					_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
-
-				}
-
-			} else if ( texture instanceof THREE.CompressedTexture ) {
-
-				// compressed textures can only use manually created mipmaps
-				// WebGL can't generate mipmaps for DDS textures
-
-				for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
-					mipmap = mipmaps[ i ];
-					_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
-
-				}
-
-			} else { // regular Texture (image, video, canvas)
-
-				// use manually created mipmaps if available
-				// if there are no manual mipmaps
-				// set 0 level mipmap and then use GL to generate other mipmap levels
-
-				if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
-
-					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
-						mipmap = mipmaps[ i ];
-						_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
-
-					}
-
-					texture.generateMipmaps = false;
-
-				} else {
-
-					_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
-
-				}
-
-			}
-
-			if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
-
-			texture.needsUpdate = false;
-
-			if ( texture.onUpdate ) texture.onUpdate();
-
-		} else {
-
-			_gl.activeTexture( _gl.TEXTURE0 + slot );
-			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-
-		}
-
-	};
-
-	function clampToMaxSize ( image, maxSize ) {
-
-		if ( image.width <= maxSize && image.height <= maxSize ) {
-
-			return image;
-
-		}
-
-		// Warning: Scaling through the canvas will only work with images that use
-		// premultiplied alpha.
-
-		var maxDimension = Math.max( image.width, image.height );
-		var newWidth = Math.floor( image.width * maxSize / maxDimension );
-		var newHeight = Math.floor( image.height * maxSize / maxDimension );
-
-		var canvas = document.createElement( 'canvas' );
-		canvas.width = newWidth;
-		canvas.height = newHeight;
-
-		var ctx = canvas.getContext( "2d" );
-		ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
-
-		return canvas;
-
-	}
-
-	function setCubeTexture ( texture, slot ) {
-
-		if ( texture.image.length === 6 ) {
-
-			if ( texture.needsUpdate ) {
-
-				if ( ! texture.image.__webglTextureCube ) {
-
-					texture.image.__webglTextureCube = _gl.createTexture();
-
-					_this.info.memory.textures ++;
-
-				}
-
-				_gl.activeTexture( _gl.TEXTURE0 + slot );
-				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
-
-				_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
-
-				var isCompressed = texture instanceof THREE.CompressedTexture;
-
-				var cubeImage = [];
-
-				for ( var i = 0; i < 6; i ++ ) {
-
-					if ( _this.autoScaleCubemaps && ! isCompressed ) {
-
-						cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
-
-					} else {
-
-						cubeImage[ i ] = texture.image[ i ];
-
-					}
-
-				}
-
-				var image = cubeImage[ 0 ],
-				isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
-				glFormat = paramThreeToGL( texture.format ),
-				glType = paramThreeToGL( texture.type );
-
-				setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
-
-				for ( var i = 0; i < 6; i ++ ) {
-
-					if ( isCompressed ) {
-
-						var mipmap, mipmaps = cubeImage[ i ].mipmaps;
-
-						for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
-
-							mipmap = mipmaps[ j ];
-							_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
-
-						}
-
-					} else {
-
-						_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
-
-					}
-
-				}
-
-				if ( texture.generateMipmaps && isImagePowerOfTwo ) {
-
-					_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
-
-				}
-
-				texture.needsUpdate = false;
-
-				if ( texture.onUpdate ) texture.onUpdate();
-
-			} else {
-
-				_gl.activeTexture( _gl.TEXTURE0 + slot );
-				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
-
-			}
-
-		}
-
-	};
-
-	function setCubeTextureDynamic ( texture, slot ) {
-
-		_gl.activeTexture( _gl.TEXTURE0 + slot );
-		_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
-
-	};
-
-	// Render targets
-
-	function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
-
-		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
-
-	};
-
-	function setupRenderBuffer ( renderbuffer, renderTarget  ) {
-
-		_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
-
-		if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
-
-			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
-			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
-
-		/* For some reason this is not working. Defaulting to RGBA4.
-		} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
-			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
-			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
-		*/
-		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
-			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
-			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
-
-		} else {
-
-			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
-
-		}
-
-	};
-
-	this.setRenderTarget = function ( renderTarget ) {
-
-		var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
-
-		if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
-
-			if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
-			if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
-
-			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
-
-			renderTarget.__webglTexture = _gl.createTexture();
-
-			_this.info.memory.textures ++;
-
-			// Setup texture, create render and frame buffers
-
-			var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
-				glFormat = paramThreeToGL( renderTarget.format ),
-				glType = paramThreeToGL( renderTarget.type );
-
-			if ( isCube ) {
-
-				renderTarget.__webglFramebuffer = [];
-				renderTarget.__webglRenderbuffer = [];
-
-				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
-				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
-
-				for ( var i = 0; i < 6; i ++ ) {
-
-					renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
-					renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
-
-					_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
-
-					setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
-					setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
-
-				}
-
-				if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
-
-			} else {
-
-				renderTarget.__webglFramebuffer = _gl.createFramebuffer();
-
-				if ( renderTarget.shareDepthFrom ) {
-
-					renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
-
-				} else {
-
-					renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
-
-				}
-
-				_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
-				setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
-
-				_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
-
-				setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
-
-				if ( renderTarget.shareDepthFrom ) {
-
-					if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
-
-						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
-
-					} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
-						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
-
-					}
-
-				} else {
-
-					setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
-
-				}
-
-				if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
-
-			}
-
-			// Release everything
-
-			if ( isCube ) {
-
-				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
-
-			} else {
-
-				_gl.bindTexture( _gl.TEXTURE_2D, null );
-
-			}
-
-			_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
-			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
-
-		}
-
-		var framebuffer, width, height, vx, vy;
-
-		if ( renderTarget ) {
-
-			if ( isCube ) {
-
-				framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
-
-			} else {
-
-				framebuffer = renderTarget.__webglFramebuffer;
-
-			}
-
-			width = renderTarget.width;
-			height = renderTarget.height;
-
-			vx = 0;
-			vy = 0;
-
-		} else {
-
-			framebuffer = null;
-
-			width = _viewportWidth;
-			height = _viewportHeight;
-
-			vx = _viewportX;
-			vy = _viewportY;
-
-		}
-
-		if ( framebuffer !== _currentFramebuffer ) {
-
-			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-			_gl.viewport( vx, vy, width, height );
-
-			_currentFramebuffer = framebuffer;
-
-		}
-
-		_currentWidth = width;
-		_currentHeight = height;
-
-	};
-
-	function updateRenderTargetMipmap ( renderTarget ) {
-
-		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
-
-			_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
-			_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
-			_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
-
-		} else {
-
-			_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
-			_gl.generateMipmap( _gl.TEXTURE_2D );
-			_gl.bindTexture( _gl.TEXTURE_2D, null );
-
-		}
-
-	};
-
-	// Fallback filters for non-power-of-2 textures
-
-	function filterFallback ( f ) {
-
-		if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
-
-			return _gl.NEAREST;
-
-		}
-
-		return _gl.LINEAR;
-
-	};
-
-	// Map three.js constants to WebGL constants
-
-	function paramThreeToGL ( p ) {
-
-		if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
-		if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
-		if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
-
-		if ( p === THREE.NearestFilter ) return _gl.NEAREST;
-		if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
-		if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
-
-		if ( p === THREE.LinearFilter ) return _gl.LINEAR;
-		if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
-		if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
-
-		if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
-		if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
-		if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
-		if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
-
-		if ( p === THREE.ByteType ) return _gl.BYTE;
-		if ( p === THREE.ShortType ) return _gl.SHORT;
-		if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
-		if ( p === THREE.IntType ) return _gl.INT;
-		if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
-		if ( p === THREE.FloatType ) return _gl.FLOAT;
-
-		if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
-		if ( p === THREE.RGBFormat ) return _gl.RGB;
-		if ( p === THREE.RGBAFormat ) return _gl.RGBA;
-		if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
-		if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
-
-		if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
-		if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
-		if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
-
-		if ( p === THREE.ZeroFactor ) return _gl.ZERO;
-		if ( p === THREE.OneFactor ) return _gl.ONE;
-		if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
-		if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
-		if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
-		if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
-		if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
-		if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
-
-		if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
-		if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
-		if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
-
-		if ( _glExtensionCompressedTextureS3TC !== undefined ) {
-
-			if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
-			if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
-			if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
-			if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
-
-		}
-
-		return 0;
-
-	};
-
-	// Allocations
-
-	function allocateBones ( object ) {
-
-		if ( _supportsBoneTextures && object && object.useVertexTexture ) {
-
-			return 1024;
-
-		} else {
-
-			// default for when object is not specified
-			// ( for example when prebuilding shader
-			//   to be used with multiple objects )
-			//
-			// 	- leave some extra space for other uniforms
-			//  - limit here is ANGLE's 254 max uniform vectors
-			//    (up to 54 should be safe)
-
-			var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
-			var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
-
-			var maxBones = nVertexMatrices;
-
-			if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
-
-				maxBones = Math.min( object.bones.length, maxBones );
-
-				if ( maxBones < object.bones.length ) {
-
-					console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
-
-				}
-
-			}
-
-			return maxBones;
-
-		}
-
-	};
-
-	function allocateLights ( lights ) {
-
-		var l, ll, light, dirLights, pointLights, spotLights, hemiLights;
-
-		dirLights = pointLights = spotLights = hemiLights = 0;
-
-		for ( l = 0, ll = lights.length; l < ll; l ++ ) {
-
-			light = lights[ l ];
-
-			if ( light.onlyShadow ) continue;
-
-			if ( light instanceof THREE.DirectionalLight ) dirLights ++;
-			if ( light instanceof THREE.PointLight ) pointLights ++;
-			if ( light instanceof THREE.SpotLight ) spotLights ++;
-			if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
-
-		}
-
-		return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
-
-	};
-
-	function allocateShadows ( lights ) {
-
-		var l, ll, light, maxShadows = 0;
-
-		for ( l = 0, ll = lights.length; l < ll; l++ ) {
-
-			light = lights[ l ];
-
-			if ( ! light.castShadow ) continue;
-
-			if ( light instanceof THREE.SpotLight ) maxShadows ++;
-			if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
-
-		}
-
-		return maxShadows;
-
-	};
-
-	// Initialization
-
-	function initGL () {
-
-		try {
-
-			if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {
-
-				throw 'Error creating WebGL context.';
-
-			}
-
-		} catch ( error ) {
-
-			console.error( error );
-
-		}
-
-		_glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
-		_glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
-
-		_glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) ||
-											   _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) ||
-											   _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
-
-
-		_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
-											_gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
-											_gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
-
-		if ( ! _glExtensionTextureFloat ) {
-
-			console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
-
-		}
-
-		if ( ! _glExtensionStandardDerivatives ) {
-
-			console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
-
-		}
-
-		if ( ! _glExtensionTextureFilterAnisotropic ) {
-
-			console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
-
-		}
-
-		if ( ! _glExtensionCompressedTextureS3TC ) {
-
-			console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
-
-		}
-
-		if ( _gl.getShaderPrecisionFormat === undefined ) {
-
-			_gl.getShaderPrecisionFormat = function() {
-
-				return {
-					"rangeMin"  : 1,
-					"rangeMax"  : 1,
-					"precision" : 1
-				};
-
-			}
-		}
-
-	};
-
-	function setDefaultGLState () {
-
-		_gl.clearColor( 0, 0, 0, 1 );
-		_gl.clearDepth( 1 );
-		_gl.clearStencil( 0 );
-
-		_gl.enable( _gl.DEPTH_TEST );
-		_gl.depthFunc( _gl.LEQUAL );
-
-		_gl.frontFace( _gl.CCW );
-		_gl.cullFace( _gl.BACK );
-		_gl.enable( _gl.CULL_FACE );
-
-		_gl.enable( _gl.BLEND );
-		_gl.blendEquation( _gl.FUNC_ADD );
-		_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
-
-		_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
-
-	};
-
-	// default plugins (order is important)
-
-	this.shadowMapPlugin = new THREE.ShadowMapPlugin();
-	this.addPrePlugin( this.shadowMapPlugin );
-
-	this.addPostPlugin( new THREE.SpritePlugin() );
-	this.addPostPlugin( new THREE.LensFlarePlugin() );
-
-};
-/**
- * @author szimek / https://github.com/szimek/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.WebGLRenderTarget = function ( width, height, options ) {
-
-	this.width = width;
-	this.height = height;
-
-	options = options || {};
-
-	this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;
-	this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;
-
-	this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;
-	this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;
-
-	this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;
-
-	this.offset = new THREE.Vector2( 0, 0 );
-	this.repeat = new THREE.Vector2( 1, 1 );
-
-	this.format = options.format !== undefined ? options.format : THREE.RGBAFormat;
-	this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;
-
-	this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
-	this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
-
-	this.generateMipmaps = true;
-
-	this.shareDepthFrom = null;
-
-};
-
-THREE.WebGLRenderTarget.prototype = {
-
-	constructor: THREE.WebGLRenderTarget,
-
-	addEventListener: THREE.EventDispatcher.prototype.addEventListener,
-	hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
-	removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
-	dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
-
-	clone: function () {
-
-		var tmp = new THREE.WebGLRenderTarget( this.width, this.height );
-
-		tmp.wrapS = this.wrapS;
-		tmp.wrapT = this.wrapT;
-
-		tmp.magFilter = this.magFilter;
-		tmp.minFilter = this.minFilter;
-
-		tmp.anisotropy = this.anisotropy;
-
-		tmp.offset.copy( this.offset );
-		tmp.repeat.copy( this.repeat );
-
-		tmp.format = this.format;
-		tmp.type = this.type;
-
-		tmp.depthBuffer = this.depthBuffer;
-		tmp.stencilBuffer = this.stencilBuffer;
-
-		tmp.generateMipmaps = this.generateMipmaps;
-
-		tmp.shareDepthFrom = this.shareDepthFrom;
-
-		return tmp;
-
-	},
-
-	dispose: function () {
-
-		this.dispatchEvent( { type: 'dispose' } );
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com
- */
-
-THREE.WebGLRenderTargetCube = function ( width, height, options ) {
-
-	THREE.WebGLRenderTarget.call( this, width, height, options );
-
-	this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
-
-};
-
-THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableVertex = function () {
-
-	this.positionWorld = new THREE.Vector3();
-	this.positionScreen = new THREE.Vector4();
-
-	this.visible = true;
-
-};
-
-THREE.RenderableVertex.prototype.copy = function ( vertex ) {
-
-	this.positionWorld.copy( vertex.positionWorld );
-	this.positionScreen.copy( vertex.positionScreen );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableFace3 = function () {
-
-	this.v1 = new THREE.RenderableVertex();
-	this.v2 = new THREE.RenderableVertex();
-	this.v3 = new THREE.RenderableVertex();
-
-	this.centroidModel = new THREE.Vector3();
-
-	this.normalModel = new THREE.Vector3();
-	this.normalModelView = new THREE.Vector3();
-
-	this.vertexNormalsLength = 0;
-	this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-	this.vertexNormalsModelView = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-
-	this.color = null;
-	this.material = null;
-	this.uvs = [[]];
-
-	this.z = null;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableFace4 = function () {
-
-	this.v1 = new THREE.RenderableVertex();
-	this.v2 = new THREE.RenderableVertex();
-	this.v3 = new THREE.RenderableVertex();
-	this.v4 = new THREE.RenderableVertex();
-
-	this.centroidModel = new THREE.Vector3();
-
-	this.normalModel = new THREE.Vector3();
-	this.normalModelView = new THREE.Vector3();
-
-	this.vertexNormalsLength = 0;
-	this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-	this.vertexNormalsModelView = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
-
-	this.color = null;
-	this.material = null;
-	this.uvs = [[]];
-
-	this.z = null;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableObject = function () {
-
-	this.object = null;
-	this.z = null;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableParticle = function () {
-
-	this.object = null;
-
-	this.x = null;
-	this.y = null;
-	this.z = null;
-
-	this.rotation = null;
-	this.scale = new THREE.Vector2();
-
-	this.material = null;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.RenderableLine = function () {
-
-	this.z = null;
-
-	this.v1 = new THREE.RenderableVertex();
-	this.v2 = new THREE.RenderableVertex();
-
-	this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
-	this.material = null;
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.GeometryUtils = {
-
-	// Merge two geometries or geometry and geometry from object (using object's transform)
-
-	merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) {
-
-		var matrix, normalMatrix,
-		vertexOffset = geometry1.vertices.length,
-		uvPosition = geometry1.faceVertexUvs[ 0 ].length,
-		geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
-		vertices1 = geometry1.vertices,
-		vertices2 = geometry2.vertices,
-		faces1 = geometry1.faces,
-		faces2 = geometry2.faces,
-		uvs1 = geometry1.faceVertexUvs[ 0 ],
-		uvs2 = geometry2.faceVertexUvs[ 0 ];
-
-		if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
-
-		if ( object2 instanceof THREE.Mesh ) {
-
-			object2.matrixAutoUpdate && object2.updateMatrix();
-
-			matrix = object2.matrix;
-
-			normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
-
-		}
-
-		// vertices
-
-		for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
-
-			var vertex = vertices2[ i ];
-
-			var vertexCopy = vertex.clone();
-
-			if ( matrix ) vertexCopy.applyMatrix4( matrix );
-
-			vertices1.push( vertexCopy );
-
-		}
-
-		// faces
-
-		for ( i = 0, il = faces2.length; i < il; i ++ ) {
-
-			var face = faces2[ i ], faceCopy, normal, color,
-			faceVertexNormals = face.vertexNormals,
-			faceVertexColors = face.vertexColors;
-
-			if ( face instanceof THREE.Face3 ) {
-
-				faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset );
-
-			}
-
-			faceCopy.normal.copy( face.normal );
-
-			if ( normalMatrix ) {
-
-				faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
-
-			}
-
-			for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
-
-				normal = faceVertexNormals[ j ].clone();
-
-				if ( normalMatrix ) {
-
-					normal.applyMatrix3( normalMatrix ).normalize();
-
-				}
-
-				faceCopy.vertexNormals.push( normal );
-
-			}
-
-			faceCopy.color.copy( face.color );
-
-			for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
-
-				color = faceVertexColors[ j ];
-				faceCopy.vertexColors.push( color.clone() );
-
-			}
-
-			faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
-
-			faceCopy.centroid.copy( face.centroid );
-
-			if ( matrix ) {
-
-				faceCopy.centroid.applyMatrix4( matrix );
-
-			}
-
-			faces1.push( faceCopy );
-
-		}
-
-		// uvs
-
-		for ( i = 0, il = uvs2.length; i < il; i ++ ) {
-
-			var uv = uvs2[ i ], uvCopy = [];
-
-			for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
-
-				uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
-
-			}
-
-			uvs1.push( uvCopy );
-
-		}
-
-	},
-
-	removeMaterials: function ( geometry, materialIndexArray ) {
-
-		var materialIndexMap = {};
-
-		for ( var i = 0, il = materialIndexArray.length; i < il; i ++ ) {
-
-			materialIndexMap[ materialIndexArray[i] ] = true;
-
-		}
-
-		var face, newFaces = [];
-
-		for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
-
-			face = geometry.faces[ i ];
-			if ( ! ( face.materialIndex in materialIndexMap ) ) newFaces.push( face );
-
-		}
-
-		geometry.faces = newFaces;
-
-	},
-
-	// Get random point in triangle (via barycentric coordinates)
-	// 	(uniform distribution)
-	// 	http://www.cgafaq.info/wiki/Random_Point_In_Triangle
-
-	randomPointInTriangle: function ( vectorA, vectorB, vectorC ) {
-
-		var a, b, c,
-			point = new THREE.Vector3(),
-			tmp = THREE.GeometryUtils.__v1;
-
-		a = THREE.GeometryUtils.random();
-		b = THREE.GeometryUtils.random();
-
-		if ( ( a + b ) > 1 ) {
-
-			a = 1 - a;
-			b = 1 - b;
-
-		}
-
-		c = 1 - a - b;
-
-		point.copy( vectorA );
-		point.multiplyScalar( a );
-
-		tmp.copy( vectorB );
-		tmp.multiplyScalar( b );
-
-		point.add( tmp );
-
-		tmp.copy( vectorC );
-		tmp.multiplyScalar( c );
-
-		point.add( tmp );
-
-		return point;
-
-	},
-
-	// Get random point in face (triangle / quad)
-	// (uniform distribution)
-
-	randomPointInFace: function ( face, geometry, useCachedAreas ) {
-
-		var vA, vB, vC, vD;
-
-		if ( face instanceof THREE.Face3 ) {
-
-			vA = geometry.vertices[ face.a ];
-			vB = geometry.vertices[ face.b ];
-			vC = geometry.vertices[ face.c ];
-
-			return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
-
-		} else if ( face instanceof THREE.Face4 ) {
-
-			vA = geometry.vertices[ face.a ];
-			vB = geometry.vertices[ face.b ];
-			vC = geometry.vertices[ face.c ];
-			vD = geometry.vertices[ face.d ];
-
-			var area1, area2;
-
-			if ( useCachedAreas ) {
-
-				if ( face._area1 && face._area2 ) {
-
-					area1 = face._area1;
-					area2 = face._area2;
-
-				} else {
-
-					area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
-					area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
-
-					face._area1 = area1;
-					face._area2 = area2;
-
-				}
-
-			} else {
-
-				area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ),
-				area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
-
-			}
-
-			var r = THREE.GeometryUtils.random() * ( area1 + area2 );
-
-			if ( r < area1 ) {
-
-				return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD );
-
-			} else {
-
-				return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD );
-
-			}
-
-		}
-
-	},
-
-	// Get uniformly distributed random points in mesh
-	// 	- create array with cumulative sums of face areas
-	//  - pick random number from 0 to total area
-	//  - find corresponding place in area array by binary search
-	//	- get random point in face
-
-	randomPointsInGeometry: function ( geometry, n ) {
-
-		var face, i,
-			faces = geometry.faces,
-			vertices = geometry.vertices,
-			il = faces.length,
-			totalArea = 0,
-			cumulativeAreas = [],
-			vA, vB, vC, vD;
-
-		// precompute face areas
-
-		for ( i = 0; i < il; i ++ ) {
-
-			face = faces[ i ];
-
-			if ( face instanceof THREE.Face3 ) {
-
-				vA = vertices[ face.a ];
-				vB = vertices[ face.b ];
-				vC = vertices[ face.c ];
-
-				face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
-
-			} else if ( face instanceof THREE.Face4 ) {
-
-				vA = vertices[ face.a ];
-				vB = vertices[ face.b ];
-				vC = vertices[ face.c ];
-				vD = vertices[ face.d ];
-
-				face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
-				face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
-
-				face._area = face._area1 + face._area2;
-
-			}
-
-			totalArea += face._area;
-
-			cumulativeAreas[ i ] = totalArea;
-
-		}
-
-		// binary search cumulative areas array
-
-		function binarySearchIndices( value ) {
-
-			function binarySearch( start, end ) {
-
-				// return closest larger index
-				// if exact number is not found
-
-				if ( end < start )
-					return start;
-
-				var mid = start + Math.floor( ( end - start ) / 2 );
-
-				if ( cumulativeAreas[ mid ] > value ) {
-
-					return binarySearch( start, mid - 1 );
-
-				} else if ( cumulativeAreas[ mid ] < value ) {
-
-					return binarySearch( mid + 1, end );
-
-				} else {
-
-					return mid;
-
-				}
-
-			}
-
-			var result = binarySearch( 0, cumulativeAreas.length - 1 )
-			return result;
-
-		}
-
-		// pick random face weighted by face area
-
-		var r, index,
-			result = [];
-
-		var stats = {};
-
-		for ( i = 0; i < n; i ++ ) {
-
-			r = THREE.GeometryUtils.random() * totalArea;
-
-			index = binarySearchIndices( r );
-
-			result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
-
-			if ( ! stats[ index ] ) {
-
-				stats[ index ] = 1;
-
-			} else {
-
-				stats[ index ] += 1;
-
-			}
-
-		}
-
-		return result;
-
-	},
-
-	// Get triangle area (half of parallelogram)
-	//	http://mathworld.wolfram.com/TriangleArea.html
-
-	triangleArea: function ( vectorA, vectorB, vectorC ) {
-
-		var tmp1 = THREE.GeometryUtils.__v1,
-			tmp2 = THREE.GeometryUtils.__v2;
-
-		tmp1.subVectors( vectorB, vectorA );
-		tmp2.subVectors( vectorC, vectorA );
-		tmp1.cross( tmp2 );
-
-		return 0.5 * tmp1.length();
-
-	},
-
-	// Center geometry so that 0,0,0 is in center of bounding box
-
-	center: function ( geometry ) {
-
-		geometry.computeBoundingBox();
-
-		var bb = geometry.boundingBox;
-
-		var offset = new THREE.Vector3();
-
-		offset.addVectors( bb.min, bb.max );
-		offset.multiplyScalar( -0.5 );
-
-		geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
-		geometry.computeBoundingBox();
-
-		return offset;
-
-	},
-
-	// Normalize UVs to be from <0,1>
-	// (for now just the first set of UVs)
-
-	normalizeUVs: function ( geometry ) {
-
-		var uvSet = geometry.faceVertexUvs[ 0 ];
-
-		for ( var i = 0, il = uvSet.length; i < il; i ++ ) {
-
-			var uvs = uvSet[ i ];
-
-			for ( var j = 0, jl = uvs.length; j < jl; j ++ ) {
-
-				// texture repeat
-
-				if( uvs[ j ].x !== 1.0 ) uvs[ j ].x = uvs[ j ].x - Math.floor( uvs[ j ].x );
-				if( uvs[ j ].y !== 1.0 ) uvs[ j ].y = uvs[ j ].y - Math.floor( uvs[ j ].y );
-
-			}
-
-		}
-
-	},
-
-	triangulateQuads: function ( geometry ) {
-
-		var i, il, j, jl;
-
-		var faces = [];
-		var faceUvs = [];
-		var faceVertexUvs = [];
-
-		for ( i = 0, il = geometry.faceUvs.length; i < il; i ++ ) {
-
-			faceUvs[ i ] = [];
-
-		}
-
-		for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
-
-			faceVertexUvs[ i ] = [];
-
-		}
-
-		for ( i = 0, il = geometry.faces.length; i < il; i ++ ) {
-
-			var face = geometry.faces[ i ];
-
-			if ( face instanceof THREE.Face4 ) {
-
-				var a = face.a;
-				var b = face.b;
-				var c = face.c;
-				var d = face.d;
-
-				var triA = new THREE.Face3();
-				var triB = new THREE.Face3();
-
-				triA.color.copy( face.color );
-				triB.color.copy( face.color );
-
-				triA.materialIndex = face.materialIndex;
-				triB.materialIndex = face.materialIndex;
-
-				triA.a = a;
-				triA.b = b;
-				triA.c = d;
-
-				triB.a = b;
-				triB.b = c;
-				triB.c = d;
-
-				if ( face.vertexColors.length === 4 ) {
-
-					triA.vertexColors[ 0 ] = face.vertexColors[ 0 ].clone();
-					triA.vertexColors[ 1 ] = face.vertexColors[ 1 ].clone();
-					triA.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone();
-
-					triB.vertexColors[ 0 ] = face.vertexColors[ 1 ].clone();
-					triB.vertexColors[ 1 ] = face.vertexColors[ 2 ].clone();
-					triB.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone();
-
-				}
-
-				faces.push( triA, triB );
-
-				for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
-
-					if ( geometry.faceVertexUvs[ j ].length ) {
-
-						var uvs = geometry.faceVertexUvs[ j ][ i ];
-
-						var uvA = uvs[ 0 ];
-						var uvB = uvs[ 1 ];
-						var uvC = uvs[ 2 ];
-						var uvD = uvs[ 3 ];
-
-						var uvsTriA = [ uvA.clone(), uvB.clone(), uvD.clone() ];
-						var uvsTriB = [ uvB.clone(), uvC.clone(), uvD.clone() ];
-
-						faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
-
-					}
-
-				}
-
-				for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) {
-
-					if ( geometry.faceUvs[ j ].length ) {
-
-						var faceUv = geometry.faceUvs[ j ][ i ];
-
-						faceUvs[ j ].push( faceUv, faceUv );
-
-					}
-
-				}
-
-			} else {
-
-				faces.push( face );
-
-				for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) {
-
-					faceUvs[ j ].push( geometry.faceUvs[ j ][ i ] );
-
-				}
-
-				for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
-
-					faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
-
-				}
-
-			}
-
-		}
-
-		geometry.faces = faces;
-		geometry.faceUvs = faceUvs;
-		geometry.faceVertexUvs = faceVertexUvs;
-
-		geometry.computeCentroids();
-		geometry.computeFaceNormals();
-		geometry.computeVertexNormals();
-
-		if ( geometry.hasTangents ) geometry.computeTangents();
-
-	},
-
-	setMaterialIndex: function ( geometry, index, startFace, endFace ){
-
-		var faces = geometry.faces;
-		var start = startFace || 0;
-		var end = endFace || faces.length - 1;
-
-		for ( var i = start; i <= end; i ++ ) {
-
-			faces[i].materialIndex = index;
-
-		}
-
-    }
-
-};
-
-THREE.GeometryUtils.random = THREE.Math.random16;
-
-THREE.GeometryUtils.__v1 = new THREE.Vector3();
-THREE.GeometryUtils.__v2 = new THREE.Vector3();
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.ImageUtils = {
-
-	crossOrigin: 'anonymous',
-
-	loadTexture: function ( url, mapping, onLoad, onError ) {
-
-		var image = new Image();
-		var texture = new THREE.Texture( image, mapping );
-
-		var loader = new THREE.ImageLoader();
-
-		loader.addEventListener( 'load', function ( event ) {
-
-			texture.image = event.content;
-			texture.needsUpdate = true;
-
-			if ( onLoad ) onLoad( texture );
-
-		} );
-
-		loader.addEventListener( 'error', function ( event ) {
-
-			if ( onError ) onError( event.message );
-
-		} );
-
-		loader.crossOrigin = this.crossOrigin;
-		loader.load( url, image );
-
-		texture.sourceFile = url;
-
-		return texture;
-
-	},
-
-	loadCompressedTexture: function ( url, mapping, onLoad, onError ) {
-
-		var texture = new THREE.CompressedTexture();
-		texture.mapping = mapping;
-
-		var request = new XMLHttpRequest();
-
-		request.onload = function () {
-
-			var buffer = request.response;
-			var dds = THREE.ImageUtils.parseDDS( buffer, true );
-
-			texture.format = dds.format;
-
-			texture.mipmaps = dds.mipmaps;
-			texture.image.width = dds.width;
-			texture.image.height = dds.height;
-
-			// gl.generateMipmap fails for compressed textures
-			// mipmaps must be embedded in the DDS file
-			// or texture filters must not use mipmapping
-
-			texture.generateMipmaps = false;
-
-			texture.needsUpdate = true;
-
-			if ( onLoad ) onLoad( texture );
-
-		}
-
-		request.onerror = onError;
-
-		request.open( 'GET', url, true );
-		request.responseType = "arraybuffer";
-		request.send( null );
-
-		return texture;
-
-	},
-
-	loadTextureCube: function ( array, mapping, onLoad, onError ) {
-
-		var images = [];
-		images.loadCount = 0;
-
-		var texture = new THREE.Texture();
-		texture.image = images;
-		if ( mapping !== undefined ) texture.mapping = mapping;
-
-		// no flipping needed for cube textures
-
-		texture.flipY = false;
-
-		for ( var i = 0, il = array.length; i < il; ++ i ) {
-
-			var cubeImage = new Image();
-			images[ i ] = cubeImage;
-
-			cubeImage.onload = function () {
-
-				images.loadCount += 1;
-
-				if ( images.loadCount === 6 ) {
-
-					texture.needsUpdate = true;
-					if ( onLoad ) onLoad( texture );
-
-				}
-
-			};
-
-			cubeImage.onerror = onError;
-
-			cubeImage.crossOrigin = this.crossOrigin;
-			cubeImage.src = array[ i ];
-
-		}
-
-		return texture;
-
-	},
-
-	loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) {
-
-		var images = [];
-		images.loadCount = 0;
-
-		var texture = new THREE.CompressedTexture();
-		texture.image = images;
-		if ( mapping !== undefined ) texture.mapping = mapping;
-
-		// no flipping for cube textures
-		// (also flipping doesn't work for compressed textures )
-
-		texture.flipY = false;
-
-		// can't generate mipmaps for compressed textures
-		// mips must be embedded in DDS files
-
-		texture.generateMipmaps = false;
-
-		var generateCubeFaceCallback = function ( rq, img ) {
-
-			return function () {
-
-				var buffer = rq.response;
-				var dds = THREE.ImageUtils.parseDDS( buffer, true );
-
-				img.format = dds.format;
-
-				img.mipmaps = dds.mipmaps;
-				img.width = dds.width;
-				img.height = dds.height;
-
-				images.loadCount += 1;
-
-				if ( images.loadCount === 6 ) {
-
-					texture.format = dds.format;
-					texture.needsUpdate = true;
-					if ( onLoad ) onLoad( texture );
-
-				}
-
-			}
-
-		}
-
-		// compressed cubemap textures as 6 separate DDS files
-
-		if ( array instanceof Array ) {
-
-			for ( var i = 0, il = array.length; i < il; ++ i ) {
-
-				var cubeImage = {};
-				images[ i ] = cubeImage;
-
-				var request = new XMLHttpRequest();
-
-				request.onload = generateCubeFaceCallback( request, cubeImage );
-				request.onerror = onError;
-
-				var url = array[ i ];
-
-				request.open( 'GET', url, true );
-				request.responseType = "arraybuffer";
-				request.send( null );
-
-			}
-
-		// compressed cubemap texture stored in a single DDS file
-
-		} else {
-
-			var url = array;
-			var request = new XMLHttpRequest();
-
-			request.onload = function( ) {
-
-				var buffer = request.response;
-				var dds = THREE.ImageUtils.parseDDS( buffer, true );
-
-				if ( dds.isCubemap ) {
-
-					var faces = dds.mipmaps.length / dds.mipmapCount;
-
-					for ( var f = 0; f < faces; f ++ ) {
-
-						images[ f ] = { mipmaps : [] };
-
-						for ( var i = 0; i < dds.mipmapCount; i ++ ) {
-
-							images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] );
-							images[ f ].format = dds.format;
-							images[ f ].width = dds.width;
-							images[ f ].height = dds.height;
-
-						}
-
-					}
-
-					texture.format = dds.format;
-					texture.needsUpdate = true;
-					if ( onLoad ) onLoad( texture );
-
-				}
-
-			}
-
-			request.onerror = onError;
-
-			request.open( 'GET', url, true );
-			request.responseType = "arraybuffer";
-			request.send( null );
-
-		}
-
-		return texture;
-
-	},
-
-	parseDDS: function ( buffer, loadMipmaps ) {
-
-		var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };
-
-		// Adapted from @toji's DDS utils
-		//	https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js
-
-		// All values and structures referenced from:
-		// http://msdn.microsoft.com/en-us/library/bb943991.aspx/
-
-		var DDS_MAGIC = 0x20534444;
-
-		var DDSD_CAPS = 0x1,
-			DDSD_HEIGHT = 0x2,
-			DDSD_WIDTH = 0x4,
-			DDSD_PITCH = 0x8,
-			DDSD_PIXELFORMAT = 0x1000,
-			DDSD_MIPMAPCOUNT = 0x20000,
-			DDSD_LINEARSIZE = 0x80000,
-			DDSD_DEPTH = 0x800000;
-
-		var DDSCAPS_COMPLEX = 0x8,
-			DDSCAPS_MIPMAP = 0x400000,
-			DDSCAPS_TEXTURE = 0x1000;
-
-		var DDSCAPS2_CUBEMAP = 0x200,
-			DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
-			DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
-			DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
-			DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
-			DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
-			DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
-			DDSCAPS2_VOLUME = 0x200000;
-
-		var DDPF_ALPHAPIXELS = 0x1,
-			DDPF_ALPHA = 0x2,
-			DDPF_FOURCC = 0x4,
-			DDPF_RGB = 0x40,
-			DDPF_YUV = 0x200,
-			DDPF_LUMINANCE = 0x20000;
-
-		function fourCCToInt32( value ) {
-
-			return value.charCodeAt(0) +
-				(value.charCodeAt(1) << 8) +
-				(value.charCodeAt(2) << 16) +
-				(value.charCodeAt(3) << 24);
-
-		}
-
-		function int32ToFourCC( value ) {
-
-			return String.fromCharCode(
-				value & 0xff,
-				(value >> 8) & 0xff,
-				(value >> 16) & 0xff,
-				(value >> 24) & 0xff
-			);
-		}
-
-		var FOURCC_DXT1 = fourCCToInt32("DXT1");
-		var FOURCC_DXT3 = fourCCToInt32("DXT3");
-		var FOURCC_DXT5 = fourCCToInt32("DXT5");
-
-		var headerLengthInt = 31; // The header length in 32 bit ints
-
-		// Offsets into the header array
-
-		var off_magic = 0;
-
-		var off_size = 1;
-		var off_flags = 2;
-		var off_height = 3;
-		var off_width = 4;
-
-		var off_mipmapCount = 7;
-
-		var off_pfFlags = 20;
-		var off_pfFourCC = 21;
-
-		var off_caps = 27;
-		var off_caps2 = 28;
-		var off_caps3 = 29;
-		var off_caps4 = 30;
-
-		// Parse header
-
-		var header = new Int32Array( buffer, 0, headerLengthInt );
-
-		if ( header[ off_magic ] !== DDS_MAGIC ) {
-
-			console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" );
-			return dds;
-
-		}
-
-		if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
-
-			console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" );
-			return dds;
-
-		}
-
-		var blockBytes;
-
-		var fourCC = header[ off_pfFourCC ];
-
-		switch ( fourCC ) {
-
-			case FOURCC_DXT1:
-
-				blockBytes = 8;
-				dds.format = THREE.RGB_S3TC_DXT1_Format;
-				break;
-
-			case FOURCC_DXT3:
-
-				blockBytes = 16;
-				dds.format = THREE.RGBA_S3TC_DXT3_Format;
-				break;
-
-			case FOURCC_DXT5:
-
-				blockBytes = 16;
-				dds.format = THREE.RGBA_S3TC_DXT5_Format;
-				break;
-
-			default:
-
-				console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) );
-				return dds;
-
-		}
-
-		dds.mipmapCount = 1;
-
-		if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
-
-			dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
-
-		}
-
-		//TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc.
-
-		dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false;
-
-		dds.width = header[ off_width ];
-		dds.height = header[ off_height ];
-
-		var dataOffset = header[ off_size ] + 4;
-
-		// Extract mipmaps buffers
-
-		var width = dds.width;
-		var height = dds.height;
-
-		var faces = dds.isCubemap ? 6 : 1;
-
-		for ( var face = 0; face < faces; face ++ ) {
-
-			for ( var i = 0; i < dds.mipmapCount; i ++ ) {
-
-				var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
-				var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
-
-				var mipmap = { "data": byteArray, "width": width, "height": height };
-				dds.mipmaps.push( mipmap );
-
-				dataOffset += dataLength;
-
-				width = Math.max( width * 0.5, 1 );
-				height = Math.max( height * 0.5, 1 );
-
-			}
-
-			width = dds.width;
-			height = dds.height;
-
-		}
-
-		return dds;
-
-	},
-
-	getNormalMap: function ( image, depth ) {
-
-		// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
-
-		var cross = function ( a, b ) {
-
-			return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
-
-		}
-
-		var subtract = function ( a, b ) {
-
-			return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
-
-		}
-
-		var normalize = function ( a ) {
-
-			var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
-			return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
-
-		}
-
-		depth = depth | 1;
-
-		var width = image.width;
-		var height = image.height;
-
-		var canvas = document.createElement( 'canvas' );
-		canvas.width = width;
-		canvas.height = height;
-
-		var context = canvas.getContext( '2d' );
-		context.drawImage( image, 0, 0 );
-
-		var data = context.getImageData( 0, 0, width, height ).data;
-		var imageData = context.createImageData( width, height );
-		var output = imageData.data;
-
-		for ( var x = 0; x < width; x ++ ) {
-
-			for ( var y = 0; y < height; y ++ ) {
-
-				var ly = y - 1 < 0 ? 0 : y - 1;
-				var uy = y + 1 > height - 1 ? height - 1 : y + 1;
-				var lx = x - 1 < 0 ? 0 : x - 1;
-				var ux = x + 1 > width - 1 ? width - 1 : x + 1;
-
-				var points = [];
-				var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
-				points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
-				points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
-				points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
-				points.push( [  1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
-				points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
-				points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
-				points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
-				points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );
-
-				var normals = [];
-				var num_points = points.length;
-
-				for ( var i = 0; i < num_points; i ++ ) {
-
-					var v1 = points[ i ];
-					var v2 = points[ ( i + 1 ) % num_points ];
-					v1 = subtract( v1, origin );
-					v2 = subtract( v2, origin );
-					normals.push( normalize( cross( v1, v2 ) ) );
-
-				}
-
-				var normal = [ 0, 0, 0 ];
-
-				for ( var i = 0; i < normals.length; i ++ ) {
-
-					normal[ 0 ] += normals[ i ][ 0 ];
-					normal[ 1 ] += normals[ i ][ 1 ];
-					normal[ 2 ] += normals[ i ][ 2 ];
-
-				}
-
-				normal[ 0 ] /= normals.length;
-				normal[ 1 ] /= normals.length;
-				normal[ 2 ] /= normals.length;
-
-				var idx = ( y * width + x ) * 4;
-
-				output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
-				output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
-				output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
-				output[ idx + 3 ] = 255;
-
-			}
-
-		}
-
-		context.putImageData( imageData, 0, 0 );
-
-		return canvas;
-
-	},
-
-	generateDataTexture: function ( width, height, color ) {
-
-		var size = width * height;
-		var data = new Uint8Array( 3 * size );
-
-		var r = Math.floor( color.r * 255 );
-		var g = Math.floor( color.g * 255 );
-		var b = Math.floor( color.b * 255 );
-
-		for ( var i = 0; i < size; i ++ ) {
-
-			data[ i * 3 ] 	  = r;
-			data[ i * 3 + 1 ] = g;
-			data[ i * 3 + 2 ] = b;
-
-		}
-
-		var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
-		texture.needsUpdate = true;
-
-		return texture;
-
-	}
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SceneUtils = {
-
-	createMultiMaterialObject: function ( geometry, materials ) {
-
-		var group = new THREE.Object3D();
-
-		for ( var i = 0, l = materials.length; i < l; i ++ ) {
-
-			group.add( new THREE.Mesh( geometry, materials[ i ] ) );
-
-		}
-
-		return group;
-
-	},
-
-	detach : function ( child, parent, scene ) {
-
-		child.applyMatrix( parent.matrixWorld );
-		parent.remove( child );
-		scene.add( child );
-
-	},
-
-	attach: function ( child, scene, parent ) {
-
-		var matrixWorldInverse = new THREE.Matrix4();
-		matrixWorldInverse.getInverse( parent.matrixWorld );
-		child.applyMatrix( matrixWorldInverse );
-
-		scene.remove( child );
-		parent.add( child );
-
-	}
-
-};
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author alteredq / http://alteredqualia.com/
- *
- * For Text operations in three.js (See TextGeometry)
- *
- * It uses techniques used in:
- *
- * 	typeface.js and canvastext
- * 		For converting fonts and rendering with javascript
- *		http://typeface.neocracy.org
- *
- *	Triangulation ported from AS3
- *		Simple Polygon Triangulation
- *		http://actionsnippet.com/?p=1462
- *
- * 	A Method to triangulate shapes with holes
- *		http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
- *
- */
-
-THREE.FontUtils = {
-
-	faces : {},
-
-	// Just for now. face[weight][style]
-
-	face : "helvetiker",
-	weight: "normal",
-	style : "normal",
-	size : 150,
-	divisions : 10,
-
-	getFace : function() {
-
-		return this.faces[ this.face ][ this.weight ][ this.style ];
-
-	},
-
-	loadFace : function( data ) {
-
-		var family = data.familyName.toLowerCase();
-
-		var ThreeFont = this;
-
-		ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
-
-		ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
-		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
-
-		var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
-
-		return data;
-
-	},
-
-	drawText : function( text ) {
-
-		var characterPts = [], allPts = [];
-
-		// RenderText
-
-		var i, p,
-			face = this.getFace(),
-			scale = this.size / face.resolution,
-			offset = 0,
-			chars = String( text ).split( '' ),
-			length = chars.length;
-
-		var fontPaths = [];
-
-		for ( i = 0; i < length; i ++ ) {
-
-			var path = new THREE.Path();
-
-			var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
-			offset += ret.offset;
-
-			fontPaths.push( ret.path );
-
-		}
-
-		// get the width
-
-		var width = offset / 2;
-		//
-		// for ( p = 0; p < allPts.length; p++ ) {
-		//
-		// 	allPts[ p ].x -= width;
-		//
-		// }
-
-		//var extract = this.extractPoints( allPts, characterPts );
-		//extract.contour = allPts;
-
-		//extract.paths = fontPaths;
-		//extract.offset = width;
-
-		return { paths : fontPaths, offset : width };
-
-	},
-
-
-
-
-	extractGlyphPoints : function( c, face, scale, offset, path ) {
-
-		var pts = [];
-
-		var i, i2, divisions,
-			outline, action, length,
-			scaleX, scaleY,
-			x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
-			laste,
-			glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
-
-		if ( !glyph ) return;
-
-		if ( glyph.o ) {
-
-			outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
-			length = outline.length;
-
-			scaleX = scale;
-			scaleY = scale;
-
-			for ( i = 0; i < length; ) {
-
-				action = outline[ i ++ ];
-
-				//console.log( action );
-
-				switch( action ) {
-
-				case 'm':
-
-					// Move To
-
-					x = outline[ i++ ] * scaleX + offset;
-					y = outline[ i++ ] * scaleY;
-
-					path.moveTo( x, y );
-					break;
-
-				case 'l':
-
-					// Line To
-
-					x = outline[ i++ ] * scaleX + offset;
-					y = outline[ i++ ] * scaleY;
-					path.lineTo(x,y);
-					break;
-
-				case 'q':
-
-					// QuadraticCurveTo
-
-					cpx  = outline[ i++ ] * scaleX + offset;
-					cpy  = outline[ i++ ] * scaleY;
-					cpx1 = outline[ i++ ] * scaleX + offset;
-					cpy1 = outline[ i++ ] * scaleY;
-
-					path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
-
-					laste = pts[ pts.length - 1 ];
-
-					if ( laste ) {
-
-						cpx0 = laste.x;
-						cpy0 = laste.y;
-
-						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
-
-							var t = i2 / divisions;
-							var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
-							var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
-					  }
-
-				  }
-
-				  break;
-
-				case 'b':
-
-					// Cubic Bezier Curve
-
-					cpx  = outline[ i++ ] *  scaleX + offset;
-					cpy  = outline[ i++ ] *  scaleY;
-					cpx1 = outline[ i++ ] *  scaleX + offset;
-					cpy1 = outline[ i++ ] * -scaleY;
-					cpx2 = outline[ i++ ] *  scaleX + offset;
-					cpy2 = outline[ i++ ] * -scaleY;
-
-					path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );
-
-					laste = pts[ pts.length - 1 ];
-
-					if ( laste ) {
-
-						cpx0 = laste.x;
-						cpy0 = laste.y;
-
-						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
-
-							var t = i2 / divisions;
-							var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
-							var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
-
-						}
-
-					}
-
-					break;
-
-				}
-
-			}
-		}
-
-
-
-		return { offset: glyph.ha*scale, path:path};
-	}
-
-};
-
-
-THREE.FontUtils.generateShapes = function( text, parameters ) {
-
-	// Parameters 
-
-	parameters = parameters || {};
-
-	var size = parameters.size !== undefined ? parameters.size : 100;
-	var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
-
-	var font = parameters.font !== undefined ? parameters.font : "helvetiker";
-	var weight = parameters.weight !== undefined ? parameters.weight : "normal";
-	var style = parameters.style !== undefined ? parameters.style : "normal";
-
-	THREE.FontUtils.size = size;
-	THREE.FontUtils.divisions = curveSegments;
-
-	THREE.FontUtils.face = font;
-	THREE.FontUtils.weight = weight;
-	THREE.FontUtils.style = style;
-
-	// Get a Font data json object
-
-	var data = THREE.FontUtils.drawText( text );
-
-	var paths = data.paths;
-	var shapes = [];
-
-	for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
-
-		Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
-
-	}
-
-	return shapes;
-
-};
-
-
-/**
- * This code is a quick port of code written in C++ which was submitted to
- * flipcode.com by John W. Ratcliff  // July 22, 2000
- * See original code and more information here:
- * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
- *
- * ported to actionscript by Zevan Rosser
- * www.actionsnippet.com
- *
- * ported to javascript by Joshua Koo
- * http://www.lab4games.net/zz85/blog
- *
- */
-
-
-( function( namespace ) {
-
-	var EPSILON = 0.0000000001;
-
-	// takes in an contour array and returns
-
-	var process = function( contour, indices ) {
-
-		var n = contour.length;
-
-		if ( n < 3 ) return null;
-
-		var result = [],
-			verts = [],
-			vertIndices = [];
-
-		/* we want a counter-clockwise polygon in verts */
-
-		var u, v, w;
-
-		if ( area( contour ) > 0.0 ) {
-
-			for ( v = 0; v < n; v++ ) verts[ v ] = v;
-
-		} else {
-
-			for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
-
-		}
-
-		var nv = n;
-
-		/*  remove nv - 2 vertices, creating 1 triangle every time */
-
-		var count = 2 * nv;   /* error detection */
-
-		for( v = nv - 1; nv > 2; ) {
-
-			/* if we loop, it is probably a non-simple polygon */
-
-			if ( ( count-- ) <= 0 ) {
-
-				//** Triangulate: ERROR - probable bad polygon!
-
-				//throw ( "Warning, unable to triangulate polygon!" );
-				//return null;
-				// Sometimes warning is fine, especially polygons are triangulated in reverse.
-				console.log( "Warning, unable to triangulate polygon!" );
-
-				if ( indices ) return vertIndices;
-				return result;
-
-			}
-
-			/* three consecutive vertices in current polygon, <u,v,w> */
-
-			u = v; 	 	if ( nv <= u ) u = 0;     /* previous */
-			v = u + 1;  if ( nv <= v ) v = 0;     /* new v    */
-			w = v + 1;  if ( nv <= w ) w = 0;     /* next     */
-
-			if ( snip( contour, u, v, w, nv, verts ) ) {
-
-				var a, b, c, s, t;
-
-				/* true names of the vertices */
-
-				a = verts[ u ];
-				b = verts[ v ];
-				c = verts[ w ];
-
-				/* output Triangle */
-
-				result.push( [ contour[ a ],
-					contour[ b ],
-					contour[ c ] ] );
-
-
-				vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
-
-				/* remove v from the remaining polygon */
-
-				for( s = v, t = v + 1; t < nv; s++, t++ ) {
-
-					verts[ s ] = verts[ t ];
-
-				}
-
-				nv--;
-
-				/* reset error detection counter */
-
-				count = 2 * nv;
-
-			}
-
-		}
-
-		if ( indices ) return vertIndices;
-		return result;
-
-	};
-
-	// calculate area of the contour polygon
-
-	var area = function ( contour ) {
-
-		var n = contour.length;
-		var a = 0.0;
-
-		for( var p = n - 1, q = 0; q < n; p = q++ ) {
-
-			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
-
-		}
-
-		return a * 0.5;
-
-	};
-
-	var snip = function ( contour, u, v, w, n, verts ) {
-
-		var p;
-		var ax, ay, bx, by;
-		var cx, cy, px, py;
-
-		ax = contour[ verts[ u ] ].x;
-		ay = contour[ verts[ u ] ].y;
-
-		bx = contour[ verts[ v ] ].x;
-		by = contour[ verts[ v ] ].y;
-
-		cx = contour[ verts[ w ] ].x;
-		cy = contour[ verts[ w ] ].y;
-
-		if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
-
-		var aX, aY, bX, bY, cX, cY;
-		var apx, apy, bpx, bpy, cpx, cpy;
-		var cCROSSap, bCROSScp, aCROSSbp;
-
-		aX = cx - bx;  aY = cy - by;
-		bX = ax - cx;  bY = ay - cy;
-		cX = bx - ax;  cY = by - ay;
-
-		for ( p = 0; p < n; p++ ) {
-
-			if( (p === u) || (p === v) || (p === w) ) continue;
-
-			px = contour[ verts[ p ] ].x
-			py = contour[ verts[ p ] ].y
-
-			apx = px - ax;  apy = py - ay;
-			bpx = px - bx;  bpy = py - by;
-			cpx = px - cx;  cpy = py - cy;
-
-			// see if p is inside triangle abc
-
-			aCROSSbp = aX*bpy - aY*bpx;
-			cCROSSap = cX*apy - cY*apx;
-			bCROSScp = bX*cpy - bY*cpx;
-
-			if ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) ) return false;
-
-		}
-
-		return true;
-
-	};
-
-
-	namespace.Triangulate = process;
-	namespace.Triangulate.area = area;
-
-	return namespace;
-
-})(THREE.FontUtils);
-
-// To use the typeface.js face files, hook up the API
-self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
-THREE.typeface_js = self._typeface_js;
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Extensible curve object
- *
- * Some common of Curve methods
- * .getPoint(t), getTangent(t)
- * .getPointAt(u), getTagentAt(u)
- * .getPoints(), .getSpacedPoints()
- * .getLength()
- * .updateArcLengths()
- *
- * This file contains following classes:
- *
- * -- 2d classes --
- * THREE.Curve
- * THREE.LineCurve
- * THREE.QuadraticBezierCurve
- * THREE.CubicBezierCurve
- * THREE.SplineCurve
- * THREE.ArcCurve
- * THREE.EllipseCurve
- *
- * -- 3d classes --
- * THREE.LineCurve3
- * THREE.QuadraticBezierCurve3
- * THREE.CubicBezierCurve3
- * THREE.SplineCurve3
- * THREE.ClosedSplineCurve3
- *
- * A series of curves can be represented as a THREE.CurvePath
- *
- **/
-
-/**************************************************************
- *	Abstract Curve base class
- **************************************************************/
-
-THREE.Curve = function () {
-
-};
-
-// Virtual base class method to overwrite and implement in subclasses
-//	- t [0 .. 1]
-
-THREE.Curve.prototype.getPoint = function ( t ) {
-
-	console.log( "Warning, getPoint() not implemented!" );
-	return null;
-
-};
-
-// Get point at relative position in curve according to arc length
-// - u [0 .. 1]
-
-THREE.Curve.prototype.getPointAt = function ( u ) {
-
-	var t = this.getUtoTmapping( u );
-	return this.getPoint( t );
-
-};
-
-// Get sequence of points using getPoint( t )
-
-THREE.Curve.prototype.getPoints = function ( divisions ) {
-
-	if ( !divisions ) divisions = 5;
-
-	var d, pts = [];
-
-	for ( d = 0; d <= divisions; d ++ ) {
-
-		pts.push( this.getPoint( d / divisions ) );
-
-	}
-
-	return pts;
-
-};
-
-// Get sequence of points using getPointAt( u )
-
-THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
-
-	if ( !divisions ) divisions = 5;
-
-	var d, pts = [];
-
-	for ( d = 0; d <= divisions; d ++ ) {
-
-		pts.push( this.getPointAt( d / divisions ) );
-
-	}
-
-	return pts;
-
-};
-
-// Get total curve arc length
-
-THREE.Curve.prototype.getLength = function () {
-
-	var lengths = this.getLengths();
-	return lengths[ lengths.length - 1 ];
-
-};
-
-// Get list of cumulative segment lengths
-
-THREE.Curve.prototype.getLengths = function ( divisions ) {
-
-	if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;
-
-	if ( this.cacheArcLengths
-		&& ( this.cacheArcLengths.length == divisions + 1 )
-		&& !this.needsUpdate) {
-
-		//console.log( "cached", this.cacheArcLengths );
-		return this.cacheArcLengths;
-
-	}
-
-	this.needsUpdate = false;
-
-	var cache = [];
-	var current, last = this.getPoint( 0 );
-	var p, sum = 0;
-
-	cache.push( 0 );
-
-	for ( p = 1; p <= divisions; p ++ ) {
-
-		current = this.getPoint ( p / divisions );
-		sum += current.distanceTo( last );
-		cache.push( sum );
-		last = current;
-
-	}
-
-	this.cacheArcLengths = cache;
-
-	return cache; // { sums: cache, sum:sum }; Sum is in the last element.
-
-};
-
-
-THREE.Curve.prototype.updateArcLengths = function() {
-	this.needsUpdate = true;
-	this.getLengths();
-};
-
-// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance
-
-THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
-
-	var arcLengths = this.getLengths();
-
-	var i = 0, il = arcLengths.length;
-
-	var targetArcLength; // The targeted u distance value to get
-
-	if ( distance ) {
-
-		targetArcLength = distance;
-
-	} else {
-
-		targetArcLength = u * arcLengths[ il - 1 ];
-
-	}
-
-	//var time = Date.now();
-
-	// binary search for the index with largest value smaller than target u distance
-
-	var low = 0, high = il - 1, comparison;
-
-	while ( low <= high ) {
-
-		i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
-
-		comparison = arcLengths[ i ] - targetArcLength;
-
-		if ( comparison < 0 ) {
-
-			low = i + 1;
-			continue;
-
-		} else if ( comparison > 0 ) {
-
-			high = i - 1;
-			continue;
-
-		} else {
-
-			high = i;
-			break;
-
-			// DONE
-
-		}
-
-	}
-
-	i = high;
-
-	//console.log('b' , i, low, high, Date.now()- time);
-
-	if ( arcLengths[ i ] == targetArcLength ) {
-
-		var t = i / ( il - 1 );
-		return t;
-
-	}
-
-	// we could get finer grain at lengths, or use simple interpolatation between two points
-
-	var lengthBefore = arcLengths[ i ];
-    var lengthAfter = arcLengths[ i + 1 ];
-
-    var segmentLength = lengthAfter - lengthBefore;
-
-    // determine where we are between the 'before' and 'after' points
-
-    var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
-
-    // add that fractional amount to t
-
-    var t = ( i + segmentFraction ) / ( il -1 );
-
-	return t;
-
-};
-
-// Returns a unit vector tangent at t
-// In case any sub curve does not implement its tangent derivation,
-// 2 points a small delta apart will be used to find its gradient
-// which seems to give a reasonable approximation
-
-THREE.Curve.prototype.getTangent = function( t ) {
-
-	var delta = 0.0001;
-	var t1 = t - delta;
-	var t2 = t + delta;
-
-	// Capping in case of danger
-
-	if ( t1 < 0 ) t1 = 0;
-	if ( t2 > 1 ) t2 = 1;
-
-	var pt1 = this.getPoint( t1 );
-	var pt2 = this.getPoint( t2 );
-
-	var vec = pt2.clone().sub(pt1);
-	return vec.normalize();
-
-};
-
-
-THREE.Curve.prototype.getTangentAt = function ( u ) {
-
-	var t = this.getUtoTmapping( u );
-	return this.getTangent( t );
-
-};
-
-/**************************************************************
- *	Line
- **************************************************************/
-
-THREE.LineCurve = function ( v1, v2 ) {
-
-	this.v1 = v1;
-	this.v2 = v2;
-
-};
-
-THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );
-
-THREE.LineCurve.prototype.getPoint = function ( t ) {
-
-	var point = this.v2.clone().sub(this.v1);
-	point.multiplyScalar( t ).add( this.v1 );
-
-	return point;
-
-};
-
-// Line curve is linear, so we can overwrite default getPointAt
-
-THREE.LineCurve.prototype.getPointAt = function ( u ) {
-
-	return this.getPoint( u );
-
-};
-
-THREE.LineCurve.prototype.getTangent = function( t ) {
-
-	var tangent = this.v2.clone().sub(this.v1);
-
-	return tangent.normalize();
-
-};
-
-/**************************************************************
- *	Quadratic Bezier curve
- **************************************************************/
-
-
-THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {
-
-	this.v0 = v0;
-	this.v1 = v1;
-	this.v2 = v2;
-
-};
-
-THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype );
-
-
-THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {
-
-	var tx, ty;
-
-	tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
-	ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
-
-	return new THREE.Vector2( tx, ty );
-
-};
-
-
-THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {
-
-	var tx, ty;
-
-	tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
-	ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );
-
-	// returns unit vector
-
-	var tangent = new THREE.Vector2( tx, ty );
-	tangent.normalize();
-
-	return tangent;
-
-};
-
-
-/**************************************************************
- *	Cubic Bezier curve
- **************************************************************/
-
-THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {
-
-	this.v0 = v0;
-	this.v1 = v1;
-	this.v2 = v2;
-	this.v3 = v3;
-
-};
-
-THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype );
-
-THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
-
-	var tx, ty;
-
-	tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
-	ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
-
-	return new THREE.Vector2( tx, ty );
-
-};
-
-THREE.CubicBezierCurve.prototype.getTangent = function( t ) {
-
-	var tx, ty;
-
-	tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
-	ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
-
-	var tangent = new THREE.Vector2( tx, ty );
-	tangent.normalize();
-
-	return tangent;
-
-};
-
-
-/**************************************************************
- *	Spline curve
- **************************************************************/
-
-THREE.SplineCurve = function ( points /* array of Vector2 */ ) {
-
-	this.points = (points == undefined) ? [] : points;
-
-};
-
-THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype );
-
-THREE.SplineCurve.prototype.getPoint = function ( t ) {
-
-	var v = new THREE.Vector2();
-	var c = [];
-	var points = this.points, point, intPoint, weight;
-	point = ( points.length - 1 ) * t;
-
-	intPoint = Math.floor( point );
-	weight = point - intPoint;
-
-	c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
-	c[ 1 ] = intPoint;
-	c[ 2 ] = intPoint  > points.length - 2 ? points.length -1 : intPoint + 1;
-	c[ 3 ] = intPoint  > points.length - 3 ? points.length -1 : intPoint + 2;
-
-	v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
-	v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );
-
-	return v;
-
-};
-
-/**************************************************************
- *	Ellipse curve
- **************************************************************/
-
-THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius,
-							aStartAngle, aEndAngle,
-							aClockwise ) {
-
-	this.aX = aX;
-	this.aY = aY;
-
-	this.xRadius = xRadius;
-	this.yRadius = yRadius;
-
-	this.aStartAngle = aStartAngle;
-	this.aEndAngle = aEndAngle;
-
-	this.aClockwise = aClockwise;
-
-};
-
-THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype );
-
-THREE.EllipseCurve.prototype.getPoint = function ( t ) {
-
-	var deltaAngle = this.aEndAngle - this.aStartAngle;
-
-	if ( !this.aClockwise ) {
-
-		t = 1 - t;
-
-	}
-
-	var angle = this.aStartAngle + t * deltaAngle;
-
-	var tx = this.aX + this.xRadius * Math.cos( angle );
-	var ty = this.aY + this.yRadius * Math.sin( angle );
-
-	return new THREE.Vector2( tx, ty );
-
-};
-
-/**************************************************************
- *	Arc curve
- **************************************************************/
-
-THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
-
-	THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
-};
-
-THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );
-
-
-/**************************************************************
- *	Utils
- **************************************************************/
-
-THREE.Curve.Utils = {
-
-	tangentQuadraticBezier: function ( t, p0, p1, p2 ) {
-
-		return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
-
-	},
-
-	// Puay Bing, thanks for helping with this derivative!
-
-	tangentCubicBezier: function (t, p0, p1, p2, p3 ) {
-
-		return -3 * p0 * (1 - t) * (1 - t)  +
-			3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) +
-			6 * t *  p2 * (1-t) - 3 * t * t * p2 +
-			3 * t * t * p3;
-	},
-
-
-	tangentSpline: function ( t, p0, p1, p2, p3 ) {
-
-		// To check if my formulas are correct
-
-		var h00 = 6 * t * t - 6 * t; 	// derived from 2t^3 − 3t^2 + 1
-		var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
-		var h01 = -6 * t * t + 6 * t; 	// − 2t3 + 3t2
-		var h11 = 3 * t * t - 2 * t;	// t3 − t2
-
-		return h00 + h10 + h01 + h11;
-
-	},
-
-	// Catmull-Rom
-
-	interpolate: function( p0, p1, p2, p3, t ) {
-
-		var v0 = ( p2 - p0 ) * 0.5;
-		var v1 = ( p3 - p1 ) * 0.5;
-		var t2 = t * t;
-		var t3 = t * t2;
-		return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
-
-	}
-
-};
-
-
-// TODO: Transformation for Curves?
-
-/**************************************************************
- *	3D Curves
- **************************************************************/
-
-// A Factory method for creating new curve subclasses
-
-THREE.Curve.create = function ( constructor, getPointFunc ) {
-
-	constructor.prototype = Object.create( THREE.Curve.prototype );
-	constructor.prototype.getPoint = getPointFunc;
-
-	return constructor;
-
-};
-
-
-/**************************************************************
- *	Line3D
- **************************************************************/
-
-THREE.LineCurve3 = THREE.Curve.create(
-
-	function ( v1, v2 ) {
-
-		this.v1 = v1;
-		this.v2 = v2;
-
-	},
-
-	function ( t ) {
-
-		var r = new THREE.Vector3();
-
-
-		r.subVectors( this.v2, this.v1 ); // diff
-		r.multiplyScalar( t );
-		r.add( this.v1 );
-
-		return r;
-
-	}
-
-);
-
-
-/**************************************************************
- *	Quadratic Bezier 3D curve
- **************************************************************/
-
-THREE.QuadraticBezierCurve3 = THREE.Curve.create(
-
-	function ( v0, v1, v2 ) {
-
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
-
-	},
-
-	function ( t ) {
-
-		var tx, ty, tz;
-
-		tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
-		ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
-		tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );
-
-		return new THREE.Vector3( tx, ty, tz );
-
-	}
-
-);
-
-
-
-/**************************************************************
- *	Cubic Bezier 3D curve
- **************************************************************/
-
-THREE.CubicBezierCurve3 = THREE.Curve.create(
-
-	function ( v0, v1, v2, v3 ) {
-
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
-		this.v3 = v3;
-
-	},
-
-	function ( t ) {
-
-		var tx, ty, tz;
-
-		tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
-		ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
-		tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );
-
-		return new THREE.Vector3( tx, ty, tz );
-
-	}
-
-);
-
-
-
-/**************************************************************
- *	Spline 3D curve
- **************************************************************/
-
-
-THREE.SplineCurve3 = THREE.Curve.create(
-
-	function ( points /* array of Vector3 */) {
-
-		this.points = (points == undefined) ? [] : points;
-
-	},
-
-	function ( t ) {
-
-		var v = new THREE.Vector3();
-		var c = [];
-		var points = this.points, point, intPoint, weight;
-		point = ( points.length - 1 ) * t;
-
-		intPoint = Math.floor( point );
-		weight = point - intPoint;
-
-		c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
-		c[ 1 ] = intPoint;
-		c[ 2 ] = intPoint  > points.length - 2 ? points.length - 1 : intPoint + 1;
-		c[ 3 ] = intPoint  > points.length - 3 ? points.length - 1 : intPoint + 2;
-
-		var pt0 = points[ c[0] ],
-			pt1 = points[ c[1] ],
-			pt2 = points[ c[2] ],
-			pt3 = points[ c[3] ];
-
-		v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
-		v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
-		v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);
-
-		return v;
-
-	}
-
-);
-
-
-// THREE.SplineCurve3.prototype.getTangent = function(t) {
-// 		var v = new THREE.Vector3();
-// 		var c = [];
-// 		var points = this.points, point, intPoint, weight;
-// 		point = ( points.length - 1 ) * t;
-
-// 		intPoint = Math.floor( point );
-// 		weight = point - intPoint;
-
-// 		c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
-// 		c[ 1 ] = intPoint;
-// 		c[ 2 ] = intPoint  > points.length - 2 ? points.length - 1 : intPoint + 1;
-// 		c[ 3 ] = intPoint  > points.length - 3 ? points.length - 1 : intPoint + 2;
-
-// 		var pt0 = points[ c[0] ],
-// 			pt1 = points[ c[1] ],
-// 			pt2 = points[ c[2] ],
-// 			pt3 = points[ c[3] ];
-
-// 	// t = weight;
-// 	v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x );
-// 	v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y );
-// 	v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z );
-
-// 	return v;
-
-// }
-
-/**************************************************************
- *	Closed Spline 3D curve
- **************************************************************/
-
-
-THREE.ClosedSplineCurve3 = THREE.Curve.create(
-
-	function ( points /* array of Vector3 */) {
-
-		this.points = (points == undefined) ? [] : points;
-
-	},
-
-    function ( t ) {
-
-        var v = new THREE.Vector3();
-        var c = [];
-        var points = this.points, point, intPoint, weight;
-        point = ( points.length - 0 ) * t;
-            // This needs to be from 0-length +1
-
-        intPoint = Math.floor( point );
-        weight = point - intPoint;
-
-        intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
-        c[ 0 ] = ( intPoint - 1 ) % points.length;
-        c[ 1 ] = ( intPoint ) % points.length;
-        c[ 2 ] = ( intPoint + 1 ) % points.length;
-        c[ 3 ] = ( intPoint + 2 ) % points.length;
-
-        v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
-        v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );
-        v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight );
-
-        return v;
-
-    }
-
-);
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- **/
-
-/**************************************************************
- *	Curved Path - a curve path is simply a array of connected
- *  curves, but retains the api of a curve
- **************************************************************/
-
-THREE.CurvePath = function () {
-
-	this.curves = [];
-	this.bends = [];
-	
-	this.autoClose = false; // Automatically closes the path
-};
-
-THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );
-
-THREE.CurvePath.prototype.add = function ( curve ) {
-
-	this.curves.push( curve );
-
-};
-
-THREE.CurvePath.prototype.checkConnection = function() {
-	// TODO
-	// If the ending of curve is not connected to the starting
-	// or the next curve, then, this is not a real path
-};
-
-THREE.CurvePath.prototype.closePath = function() {
-	// TODO Test
-	// and verify for vector3 (needs to implement equals)
-	// Add a line curve if start and end of lines are not connected
-	var startPoint = this.curves[0].getPoint(0);
-	var endPoint = this.curves[this.curves.length-1].getPoint(1);
-	
-	if (!startPoint.equals(endPoint)) {
-		this.curves.push( new THREE.LineCurve(endPoint, startPoint) );
-	}
-	
-};
-
-// To get accurate point with reference to
-// entire path distance at time t,
-// following has to be done:
-
-// 1. Length of each sub path have to be known
-// 2. Locate and identify type of curve
-// 3. Get t for the curve
-// 4. Return curve.getPointAt(t')
-
-THREE.CurvePath.prototype.getPoint = function( t ) {
-
-	var d = t * this.getLength();
-	var curveLengths = this.getCurveLengths();
-	var i = 0, diff, curve;
-
-	// To think about boundaries points.
-
-	while ( i < curveLengths.length ) {
-
-		if ( curveLengths[ i ] >= d ) {
-
-			diff = curveLengths[ i ] - d;
-			curve = this.curves[ i ];
-
-			var u = 1 - diff / curve.getLength();
-
-			return curve.getPointAt( u );
-
-			break;
-		}
-
-		i ++;
-
-	}
-
-	return null;
-
-	// loop where sum != 0, sum > d , sum+1 <d
-
-};
-
-/*
-THREE.CurvePath.prototype.getTangent = function( t ) {
-};*/
-
-
-// We cannot use the default THREE.Curve getPoint() with getLength() because in
-// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
-// getPoint() depends on getLength
-
-THREE.CurvePath.prototype.getLength = function() {
-
-	var lens = this.getCurveLengths();
-	return lens[ lens.length - 1 ];
-
-};
-
-// Compute lengths and cache them
-// We cannot overwrite getLengths() because UtoT mapping uses it.
-
-THREE.CurvePath.prototype.getCurveLengths = function() {
-
-	// We use cache values if curves and cache array are same length
-
-	if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) {
-
-		return this.cacheLengths;
-
-	};
-
-	// Get length of subsurve
-	// Push sums into cached array
-
-	var lengths = [], sums = 0;
-	var i, il = this.curves.length;
-
-	for ( i = 0; i < il; i ++ ) {
-
-		sums += this.curves[ i ].getLength();
-		lengths.push( sums );
-
-	}
-
-	this.cacheLengths = lengths;
-
-	return lengths;
-
-};
-
-
-
-// Returns min and max coordinates, as well as centroid
-
-THREE.CurvePath.prototype.getBoundingBox = function () {
-
-	var points = this.getPoints();
-
-	var maxX, maxY, maxZ;
-	var minX, minY, minZ;
-
-	maxX = maxY = Number.NEGATIVE_INFINITY;
-	minX = minY = Number.POSITIVE_INFINITY;
-
-	var p, i, il, sum;
-
-	var v3 = points[0] instanceof THREE.Vector3;
-
-	sum = v3 ? new THREE.Vector3() : new THREE.Vector2();
-
-	for ( i = 0, il = points.length; i < il; i ++ ) {
-
-		p = points[ i ];
-
-		if ( p.x > maxX ) maxX = p.x;
-		else if ( p.x < minX ) minX = p.x;
-
-		if ( p.y > maxY ) maxY = p.y;
-		else if ( p.y < minY ) minY = p.y;
-
-		if ( v3 ) {
-
-			if ( p.z > maxZ ) maxZ = p.z;
-			else if ( p.z < minZ ) minZ = p.z;
-
-		}
-
-		sum.add( p );
-
-	}
-
-	var ret = {
-
-		minX: minX,
-		minY: minY,
-		maxX: maxX,
-		maxY: maxY,
-		centroid: sum.divideScalar( il )
-
-	};
-
-	if ( v3 ) {
-
-		ret.maxZ = maxZ;
-		ret.minZ = minZ;
-
-	}
-
-	return ret;
-
-};
-
-/**************************************************************
- *	Create Geometries Helpers
- **************************************************************/
-
-/// Generate geometry from path points (for Line or ParticleSystem objects)
-
-THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {
-
-	var pts = this.getPoints( divisions, true );
-	return this.createGeometry( pts );
-
-};
-
-// Generate geometry from equidistance sampling along the path
-
-THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {
-
-	var pts = this.getSpacedPoints( divisions, true );
-	return this.createGeometry( pts );
-
-};
-
-THREE.CurvePath.prototype.createGeometry = function( points ) {
-
-	var geometry = new THREE.Geometry();
-
-	for ( var i = 0; i < points.length; i ++ ) {
-
-		geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );
-
-	}
-
-	return geometry;
-
-};
-
-
-/**************************************************************
- *	Bend / Wrap Helper Methods
- **************************************************************/
-
-// Wrap path / Bend modifiers?
-
-THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {
-
-	this.bends.push( bendpath );
-
-};
-
-THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {
-
-	var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
-	var i, il;
-
-	if ( !bends ) {
-
-		bends = this.bends;
-
-	}
-
-	for ( i = 0, il = bends.length; i < il; i ++ ) {
-
-		oldPts = this.getWrapPoints( oldPts, bends[ i ] );
-
-	}
-
-	return oldPts;
-
-};
-
-THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {
-
-	var oldPts = this.getSpacedPoints( segments );
-
-	var i, il;
-
-	if ( !bends ) {
-
-		bends = this.bends;
-
-	}
-
-	for ( i = 0, il = bends.length; i < il; i ++ ) {
-
-		oldPts = this.getWrapPoints( oldPts, bends[ i ] );
-
-	}
-
-	return oldPts;
-
-};
-
-// This returns getPoints() bend/wrapped around the contour of a path.
-// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html
-
-THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {
-
-	var bounds = this.getBoundingBox();
-
-	var i, il, p, oldX, oldY, xNorm;
-
-	for ( i = 0, il = oldPts.length; i < il; i ++ ) {
-
-		p = oldPts[ i ];
-
-		oldX = p.x;
-		oldY = p.y;
-
-		xNorm = oldX / bounds.maxX;
-
-		// If using actual distance, for length > path, requires line extrusions
-		//xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance
-
-		xNorm = path.getUtoTmapping( xNorm, oldX );
-
-		// check for out of bounds?
-
-		var pathPt = path.getPoint( xNorm );
-		var normal = path.getNormalVector( xNorm ).multiplyScalar( oldY );
-
-		p.x = pathPt.x + normal.x;
-		p.y = pathPt.y + normal.y;
-
-	}
-
-	return oldPts;
-
-};
-
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Gyroscope = function () {
-
-	THREE.Object3D.call( this );
-
-};
-
-THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) {
-
-	this.matrixAutoUpdate && this.updateMatrix();
-
-	// update matrixWorld
-
-	if ( this.matrixWorldNeedsUpdate || force ) {
-
-		if ( this.parent ) {
-
-			this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
-
-			this.matrixWorld.decompose( this.translationWorld, this.rotationWorld, this.scaleWorld );
-			this.matrix.decompose( this.translationObject, this.rotationObject, this.scaleObject );
-
-			this.matrixWorld.makeFromPositionQuaternionScale( this.translationWorld, this.rotationObject, this.scaleWorld );
-
-
-		} else {
-
-			this.matrixWorld.copy( this.matrix );
-
-		}
-
-
-		this.matrixWorldNeedsUpdate = false;
-
-		force = true;
-
-	}
-
-	// update children
-
-	for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-		this.children[ i ].updateMatrixWorld( force );
-
-	}
-
-};
-
-THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3();
-THREE.Gyroscope.prototype.translationObject = new THREE.Vector3();
-THREE.Gyroscope.prototype.rotationWorld = new THREE.Quaternion();
-THREE.Gyroscope.prototype.rotationObject = new THREE.Quaternion();
-THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3();
-THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3();
-
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Creates free form 2d path using series of points, lines or curves.
- *
- **/
-
-THREE.Path = function ( points ) {
-
-	THREE.CurvePath.call(this);
-
-	this.actions = [];
-
-	if ( points ) {
-
-		this.fromPoints( points );
-
-	}
-
-};
-
-THREE.Path.prototype = Object.create( THREE.CurvePath.prototype );
-
-THREE.PathActions = {
-
-	MOVE_TO: 'moveTo',
-	LINE_TO: 'lineTo',
-	QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
-	BEZIER_CURVE_TO: 'bezierCurveTo', 		// Bezier cubic curve
-	CSPLINE_THRU: 'splineThru',				// Catmull-rom spline
-	ARC: 'arc',								// Circle
-	ELLIPSE: 'ellipse'
-};
-
-// TODO Clean up PATH API
-
-// Create path using straight lines to connect all points
-// - vectors: array of Vector2
-
-THREE.Path.prototype.fromPoints = function ( vectors ) {
-
-	this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
-
-	for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {
-
-		this.lineTo( vectors[ v ].x, vectors[ v ].y );
-
-	};
-
-};
-
-// startPath() endPath()?
-
-THREE.Path.prototype.moveTo = function ( x, y ) {
-
-	var args = Array.prototype.slice.call( arguments );
-	this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );
-
-};
-
-THREE.Path.prototype.lineTo = function ( x, y ) {
-
-	var args = Array.prototype.slice.call( arguments );
-
-	var lastargs = this.actions[ this.actions.length - 1 ].args;
-
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-
-	var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
-	this.curves.push( curve );
-
-	this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );
-
-};
-
-THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {
-
-	var args = Array.prototype.slice.call( arguments );
-
-	var lastargs = this.actions[ this.actions.length - 1 ].args;
-
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-
-	var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
-												new THREE.Vector2( aCPx, aCPy ),
-												new THREE.Vector2( aX, aY ) );
-	this.curves.push( curve );
-
-	this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );
-
-};
-
-THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,
-                                               aCP2x, aCP2y,
-                                               aX, aY ) {
-
-	var args = Array.prototype.slice.call( arguments );
-
-	var lastargs = this.actions[ this.actions.length - 1 ].args;
-
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-
-	var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),
-											new THREE.Vector2( aCP1x, aCP1y ),
-											new THREE.Vector2( aCP2x, aCP2y ),
-											new THREE.Vector2( aX, aY ) );
-	this.curves.push( curve );
-
-	this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );
-
-};
-
-THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {
-
-	var args = Array.prototype.slice.call( arguments );
-	var lastargs = this.actions[ this.actions.length - 1 ].args;
-
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-//---
-	var npts = [ new THREE.Vector2( x0, y0 ) ];
-	Array.prototype.push.apply( npts, pts );
-
-	var curve = new THREE.SplineCurve( npts );
-	this.curves.push( curve );
-
-	this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );
-
-};
-
-// FUTURE: Change the API or follow canvas API?
-
-THREE.Path.prototype.arc = function ( aX, aY, aRadius,
-									  aStartAngle, aEndAngle, aClockwise ) {
-
-	var lastargs = this.actions[ this.actions.length - 1].args;
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-
-	this.absarc(aX + x0, aY + y0, aRadius,
-		aStartAngle, aEndAngle, aClockwise );
-	
- };
-
- THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
-									  aStartAngle, aEndAngle, aClockwise ) {
-	this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
- };
- 
-THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
-									  aStartAngle, aEndAngle, aClockwise ) {
-
-	var lastargs = this.actions[ this.actions.length - 1].args;
-	var x0 = lastargs[ lastargs.length - 2 ];
-	var y0 = lastargs[ lastargs.length - 1 ];
-
-	this.absellipse(aX + x0, aY + y0, xRadius, yRadius,
-		aStartAngle, aEndAngle, aClockwise );
-
- };
- 
-
-THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,
-									  aStartAngle, aEndAngle, aClockwise ) {
-
-	var args = Array.prototype.slice.call( arguments );
-	var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
-									aStartAngle, aEndAngle, aClockwise );
-	this.curves.push( curve );
-
-	var lastPoint = curve.getPoint(aClockwise ? 1 : 0);
-	args.push(lastPoint.x);
-	args.push(lastPoint.y);
-
-	this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
-
- };
-
-THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
-
-	if ( ! divisions ) divisions = 40;
-
-	var points = [];
-
-	for ( var i = 0; i < divisions; i ++ ) {
-
-		points.push( this.getPoint( i / divisions ) );
-
-		//if( !this.getPoint( i / divisions ) ) throw "DIE";
-
-	}
-
-	// if ( closedPath ) {
-	//
-	// 	points.push( points[ 0 ] );
-	//
-	// }
-
-	return points;
-
-};
-
-/* Return an array of vectors based on contour of the path */
-
-THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
-
-	if (this.useSpacedPoints) {
-		console.log('tata');
-		return this.getSpacedPoints( divisions, closedPath );
-	}
-
-	divisions = divisions || 12;
-
-	var points = [];
-
-	var i, il, item, action, args;
-	var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
-		laste, j,
-		t, tx, ty;
-
-	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
-
-		item = this.actions[ i ];
-
-		action = item.action;
-		args = item.args;
-
-		switch( action ) {
-
-		case THREE.PathActions.MOVE_TO:
-
-			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
-
-			break;
-
-		case THREE.PathActions.LINE_TO:
-
-			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
-
-			break;
-
-		case THREE.PathActions.QUADRATIC_CURVE_TO:
-
-			cpx  = args[ 2 ];
-			cpy  = args[ 3 ];
-
-			cpx1 = args[ 0 ];
-			cpy1 = args[ 1 ];
-
-			if ( points.length > 0 ) {
-
-				laste = points[ points.length - 1 ];
-
-				cpx0 = laste.x;
-				cpy0 = laste.y;
-
-			} else {
-
-				laste = this.actions[ i - 1 ].args;
-
-				cpx0 = laste[ laste.length - 2 ];
-				cpy0 = laste[ laste.length - 1 ];
-
-			}
-
-			for ( j = 1; j <= divisions; j ++ ) {
-
-				t = j / divisions;
-
-				tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
-				ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
-
-				points.push( new THREE.Vector2( tx, ty ) );
-
-		  	}
-
-			break;
-
-		case THREE.PathActions.BEZIER_CURVE_TO:
-
-			cpx  = args[ 4 ];
-			cpy  = args[ 5 ];
-
-			cpx1 = args[ 0 ];
-			cpy1 = args[ 1 ];
-
-			cpx2 = args[ 2 ];
-			cpy2 = args[ 3 ];
-
-			if ( points.length > 0 ) {
-
-				laste = points[ points.length - 1 ];
-
-				cpx0 = laste.x;
-				cpy0 = laste.y;
-
-			} else {
-
-				laste = this.actions[ i - 1 ].args;
-
-				cpx0 = laste[ laste.length - 2 ];
-				cpy0 = laste[ laste.length - 1 ];
-
-			}
-
-
-			for ( j = 1; j <= divisions; j ++ ) {
-
-				t = j / divisions;
-
-				tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
-				ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
-
-				points.push( new THREE.Vector2( tx, ty ) );
-
-			}
-
-			break;
-
-		case THREE.PathActions.CSPLINE_THRU:
-
-			laste = this.actions[ i - 1 ].args;
-
-			var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
-			var spts = [ last ];
-
-			var n = divisions * args[ 0 ].length;
-
-			spts = spts.concat( args[ 0 ] );
-
-			var spline = new THREE.SplineCurve( spts );
-
-			for ( j = 1; j <= n; j ++ ) {
-
-				points.push( spline.getPointAt( j / n ) ) ;
-
-			}
-
-			break;
-
-		case THREE.PathActions.ARC:
-
-			var aX = args[ 0 ], aY = args[ 1 ],
-				aRadius = args[ 2 ],
-				aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
-				aClockwise = !!args[ 5 ];
-
-			var deltaAngle = aEndAngle - aStartAngle;
-			var angle;
-			var tdivisions = divisions * 2;
-
-			for ( j = 1; j <= tdivisions; j ++ ) {
-
-				t = j / tdivisions;
-
-				if ( ! aClockwise ) {
-
-					t = 1 - t;
-
-				}
-
-				angle = aStartAngle + t * deltaAngle;
-
-				tx = aX + aRadius * Math.cos( angle );
-				ty = aY + aRadius * Math.sin( angle );
-
-				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
-
-				points.push( new THREE.Vector2( tx, ty ) );
-
-			}
-
-			//console.log(points);
-
-		  break;
-		  
-		case THREE.PathActions.ELLIPSE:
-
-			var aX = args[ 0 ], aY = args[ 1 ],
-				xRadius = args[ 2 ],
-				yRadius = args[ 3 ],
-				aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
-				aClockwise = !!args[ 6 ];
-
-
-			var deltaAngle = aEndAngle - aStartAngle;
-			var angle;
-			var tdivisions = divisions * 2;
-
-			for ( j = 1; j <= tdivisions; j ++ ) {
-
-				t = j / tdivisions;
-
-				if ( ! aClockwise ) {
-
-					t = 1 - t;
-
-				}
-
-				angle = aStartAngle + t * deltaAngle;
-
-				tx = aX + xRadius * Math.cos( angle );
-				ty = aY + yRadius * Math.sin( angle );
-
-				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
-
-				points.push( new THREE.Vector2( tx, ty ) );
-
-			}
-
-			//console.log(points);
-
-		  break;
-
-		} // end switch
-
-	}
-
-
-
-	// Normalize to remove the closing point by default.
-	var lastPoint = points[ points.length - 1];
-	var EPSILON = 0.0000000001;
-	if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&
-             Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
-		points.splice( points.length - 1, 1);
-	if ( closedPath ) {
-
-		points.push( points[ 0 ] );
-
-	}
-
-	return points;
-
-};
-
-// Breaks path into shapes
-
-THREE.Path.prototype.toShapes = function() {
-
-	var i, il, item, action, args;
-
-	var subPaths = [], lastPath = new THREE.Path();
-
-	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
-
-		item = this.actions[ i ];
-
-		args = item.args;
-		action = item.action;
-
-		if ( action == THREE.PathActions.MOVE_TO ) {
-
-			if ( lastPath.actions.length != 0 ) {
-
-				subPaths.push( lastPath );
-				lastPath = new THREE.Path();
-
-			}
-
-		}
-
-		lastPath[ action ].apply( lastPath, args );
-
-	}
-
-	if ( lastPath.actions.length != 0 ) {
-
-		subPaths.push( lastPath );
-
-	}
-
-	// console.log(subPaths);
-
-	if ( subPaths.length == 0 ) return [];
-
-	var tmpPath, tmpShape, shapes = [];
-
-	var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
-	// console.log("Holes first", holesFirst);
-
-	if ( subPaths.length == 1) {
-		tmpPath = subPaths[0];
-		tmpShape = new THREE.Shape();
-		tmpShape.actions = tmpPath.actions;
-		tmpShape.curves = tmpPath.curves;
-		shapes.push( tmpShape );
-		return shapes;
-	};
-
-	if ( holesFirst ) {
-
-		tmpShape = new THREE.Shape();
-
-		for ( i = 0, il = subPaths.length; i < il; i ++ ) {
-
-			tmpPath = subPaths[ i ];
-
-			if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {
-
-				tmpShape.actions = tmpPath.actions;
-				tmpShape.curves = tmpPath.curves;
-
-				shapes.push( tmpShape );
-				tmpShape = new THREE.Shape();
-
-				//console.log('cw', i);
-
-			} else {
-
-				tmpShape.holes.push( tmpPath );
-
-				//console.log('ccw', i);
-
-			}
-
-		}
-
-	} else {
-
-		// Shapes first
-
-		for ( i = 0, il = subPaths.length; i < il; i ++ ) {
-
-			tmpPath = subPaths[ i ];
-
-			if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {
-
-
-				if ( tmpShape ) shapes.push( tmpShape );
-
-				tmpShape = new THREE.Shape();
-				tmpShape.actions = tmpPath.actions;
-				tmpShape.curves = tmpPath.curves;
-
-			} else {
-
-				tmpShape.holes.push( tmpPath );
-
-			}
-
-		}
-
-		shapes.push( tmpShape );
-
-	}
-
-	//console.log("shape", shapes);
-
-	return shapes;
-
-};
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Defines a 2d shape plane using paths.
- **/
-
-// STEP 1 Create a path.
-// STEP 2 Turn path into shape.
-// STEP 3 ExtrudeGeometry takes in Shape/Shapes
-// STEP 3a - Extract points from each shape, turn to vertices
-// STEP 3b - Triangulate each shape, add faces.
-
-THREE.Shape = function () {
-
-	THREE.Path.apply( this, arguments );
-	this.holes = [];
-
-};
-
-THREE.Shape.prototype = Object.create( THREE.Path.prototype );
-
-// Convenience method to return ExtrudeGeometry
-
-THREE.Shape.prototype.extrude = function ( options ) {
-
-	var extruded = new THREE.ExtrudeGeometry( this, options );
-	return extruded;
-
-};
-
-// Convenience method to return ShapeGeometry
-
-THREE.Shape.prototype.makeGeometry = function ( options ) {
-
-	var geometry = new THREE.ShapeGeometry( this, options );
-	return geometry;
-
-};
-
-// Get points of holes
-
-THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
-
-	var i, il = this.holes.length, holesPts = [];
-
-	for ( i = 0; i < il; i ++ ) {
-
-		holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );
-
-	}
-
-	return holesPts;
-
-};
-
-// Get points of holes (spaced by regular distance)
-
-THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
-
-	var i, il = this.holes.length, holesPts = [];
-
-	for ( i = 0; i < il; i ++ ) {
-
-		holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );
-
-	}
-
-	return holesPts;
-
-};
-
-
-// Get points of shape and holes (keypoints based on segments parameter)
-
-THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
-
-	return {
-
-		shape: this.getTransformedPoints( divisions ),
-		holes: this.getPointsHoles( divisions )
-
-	};
-
-};
-
-THREE.Shape.prototype.extractPoints = function ( divisions ) {
-
-	if (this.useSpacedPoints) {
-		return this.extractAllSpacedPoints(divisions);
-	}
-
-	return this.extractAllPoints(divisions);
-
-};
-
-//
-// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
-//
-// 	return {
-//
-// 		shape: this.transform( bend, divisions ),
-// 		holes: this.getPointsHoles( divisions, bend )
-//
-// 	};
-//
-// };
-
-// Get points of shape and holes (spaced by regular distance)
-
-THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
-
-	return {
-
-		shape: this.getTransformedSpacedPoints( divisions ),
-		holes: this.getSpacedPointsHoles( divisions )
-
-	};
-
-};
-
-/**************************************************************
- *	Utils
- **************************************************************/
-
-THREE.Shape.Utils = {
-
-	/*
-		contour - array of vector2 for contour
-		holes   - array of array of vector2
-	*/
-
-	removeHoles: function ( contour, holes ) {
-
-		var shape = contour.concat(); // work on this shape
-		var allpoints = shape.concat();
-
-		/* For each isolated shape, find the closest points and break to the hole to allow triangulation */
-
-
-		var prevShapeVert, nextShapeVert,
-			prevHoleVert, nextHoleVert,
-			holeIndex, shapeIndex,
-			shapeId, shapeGroup,
-			h, h2,
-			hole, shortest, d,
-			p, pts1, pts2,
-			tmpShape1, tmpShape2,
-			tmpHole1, tmpHole2,
-			verts = [];
-
-		for ( h = 0; h < holes.length; h ++ ) {
-
-			hole = holes[ h ];
-
-			/*
-			shapeholes[ h ].concat(); // preserves original
-			holes.push( hole );
-			*/
-
-			Array.prototype.push.apply( allpoints, hole );
-
-			shortest = Number.POSITIVE_INFINITY;
-
-
-			// Find the shortest pair of pts between shape and hole
-
-			// Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n)
-			// Using distanceToSquared() intead of distanceTo() should speed a little
-			// since running square roots operations are reduced.
-
-			for ( h2 = 0; h2 < hole.length; h2 ++ ) {
-
-				pts1 = hole[ h2 ];
-				var dist = [];
-
-				for ( p = 0; p < shape.length; p++ ) {
-
-					pts2 = shape[ p ];
-					d = pts1.distanceToSquared( pts2 );
-					dist.push( d );
-
-					if ( d < shortest ) {
-
-						shortest = d;
-						holeIndex = h2;
-						shapeIndex = p;
-
-					}
-
-				}
-
-			}
-
-			//console.log("shortest", shortest, dist);
-
-			prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
-			prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
-
-			var areaapts = [
-
-				hole[ holeIndex ],
-				shape[ shapeIndex ],
-				shape[ prevShapeVert ]
-
-			];
-
-			var areaa = THREE.FontUtils.Triangulate.area( areaapts );
-
-			var areabpts = [
-
-				hole[ holeIndex ],
-				hole[ prevHoleVert ],
-				shape[ shapeIndex ]
-
-			];
-
-			var areab = THREE.FontUtils.Triangulate.area( areabpts );
-
-			var shapeOffset = 1;
-			var holeOffset = -1;
-
-			var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex;
-			shapeIndex += shapeOffset;
-			holeIndex += holeOffset;
-
-			if ( shapeIndex < 0 ) { shapeIndex += shape.length;  }
-			shapeIndex %= shape.length;
-
-			if ( holeIndex < 0 ) { holeIndex += hole.length;  }
-			holeIndex %= hole.length;
-
-			prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
-			prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
-
-			areaapts = [
-
-				hole[ holeIndex ],
-				shape[ shapeIndex ],
-				shape[ prevShapeVert ]
-
-			];
-
-			var areaa2 = THREE.FontUtils.Triangulate.area( areaapts );
-
-			areabpts = [
-
-				hole[ holeIndex ],
-				hole[ prevHoleVert ],
-				shape[ shapeIndex ]
-
-			];
-
-			var areab2 = THREE.FontUtils.Triangulate.area( areabpts );
-			//console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ),  ( areaa2 + areab2 ));
-
-			if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) {
-
-				// In case areas are not correct.
-				//console.log("USE THIS");
-
-				shapeIndex = oldShapeIndex;
-				holeIndex = oldHoleIndex ;
-
-				if ( shapeIndex < 0 ) { shapeIndex += shape.length;  }
-				shapeIndex %= shape.length;
-
-				if ( holeIndex < 0 ) { holeIndex += hole.length;  }
-				holeIndex %= hole.length;
-
-				prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
-				prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
-
-			} else {
-
-				//console.log("USE THAT ")
-
-			}
-
-			tmpShape1 = shape.slice( 0, shapeIndex );
-			tmpShape2 = shape.slice( shapeIndex );
-			tmpHole1 = hole.slice( holeIndex );
-			tmpHole2 = hole.slice( 0, holeIndex );
-
-			// Should check orders here again?
-
-			var trianglea = [
-
-				hole[ holeIndex ],
-				shape[ shapeIndex ],
-				shape[ prevShapeVert ]
-
-			];
-
-			var triangleb = [
-
-				hole[ holeIndex ] ,
-				hole[ prevHoleVert ],
-				shape[ shapeIndex ]
-
-			];
-
-			verts.push( trianglea );
-			verts.push( triangleb );
-
-			shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
-
-		}
-
-		return {
-
-			shape:shape, 		/* shape with no holes */
-			isolatedPts: verts, /* isolated faces */
-			allpoints: allpoints
-
-		}
-
-
-	},
-
-	triangulateShape: function ( contour, holes ) {
-
-		var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes );
-
-		var shape = shapeWithoutHoles.shape,
-			allpoints = shapeWithoutHoles.allpoints,
-			isolatedPts = shapeWithoutHoles.isolatedPts;
-
-		var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape
-
-		// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
-
-		//console.log( "triangles",triangles, triangles.length );
-		//console.log( "allpoints",allpoints, allpoints.length );
-
-		var i, il, f, face,
-			key, index,
-			allPointsMap = {},
-			isolatedPointsMap = {};
-
-		// prepare all points map
-
-		for ( i = 0, il = allpoints.length; i < il; i ++ ) {
-
-			key = allpoints[ i ].x + ":" + allpoints[ i ].y;
-
-			if ( allPointsMap[ key ] !== undefined ) {
-
-				console.log( "Duplicate point", key );
-
-			}
-
-			allPointsMap[ key ] = i;
-
-		}
-
-		// check all face vertices against all points map
-
-		for ( i = 0, il = triangles.length; i < il; i ++ ) {
-
-			face = triangles[ i ];
-
-			for ( f = 0; f < 3; f ++ ) {
-
-				key = face[ f ].x + ":" + face[ f ].y;
-
-				index = allPointsMap[ key ];
-
-				if ( index !== undefined ) {
-
-					face[ f ] = index;
-
-				}
-
-			}
-
-		}
-
-		// check isolated points vertices against all points map
-
-		for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {
-
-			face = isolatedPts[ i ];
-
-			for ( f = 0; f < 3; f ++ ) {
-
-				key = face[ f ].x + ":" + face[ f ].y;
-
-				index = allPointsMap[ key ];
-
-				if ( index !== undefined ) {
-
-					face[ f ] = index;
-
-				}
-
-			}
-
-		}
-
-		return triangles.concat( isolatedPts );
-
-	}, // end triangulate shapes
-
-	/*
-	triangulate2 : function( pts, holes ) {
-
-		// For use with Poly2Tri.js
-
-		var allpts = pts.concat();
-		var shape = [];
-		for (var p in pts) {
-			shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y));
-		}
-
-		var swctx = new js.poly2tri.SweepContext(shape);
-
-		for (var h in holes) {
-			var aHole = holes[h];
-			var newHole = []
-			for (i in aHole) {
-				newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y));
-				allpts.push(aHole[i]);
-			}
-			swctx.AddHole(newHole);
-		}
-
-		var find;
-		var findIndexForPt = function (pt) {
-			find = new THREE.Vector2(pt.x, pt.y);
-			var p;
-			for (p=0, pl = allpts.length; p<pl; p++) {
-				if (allpts[p].equals(find)) return p;
-			}
-			return -1;
-		};
-
-		// triangulate
-		js.poly2tri.sweep.Triangulate(swctx);
-
-		var triangles =  swctx.GetTriangles();
-		var tr ;
-		var facesPts = [];
-		for (var t in triangles) {
-			tr =  triangles[t];
-			facesPts.push([
-				findIndexForPt(tr.GetPoint(0)),
-				findIndexForPt(tr.GetPoint(1)),
-				findIndexForPt(tr.GetPoint(2))
-					]);
-		}
-
-
-	//	console.log(facesPts);
-	//	console.log("triangles", triangles.length, triangles);
-
-		// Returns array of faces with 3 element each
-	return facesPts;
-	},
-*/
-
-	isClockWise: function ( pts ) {
-
-		return THREE.FontUtils.Triangulate.area( pts ) < 0;
-
-	},
-
-	// Bezier Curves formulas obtained from
-	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
-
-	// Quad Bezier Functions
-
-	b2p0: function ( t, p ) {
-
-		var k = 1 - t;
-		return k * k * p;
-
-	},
-
-	b2p1: function ( t, p ) {
-
-		return 2 * ( 1 - t ) * t * p;
-
-	},
-
-	b2p2: function ( t, p ) {
-
-		return t * t * p;
-
-	},
-
-	b2: function ( t, p0, p1, p2 ) {
-
-		return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
-
-	},
-
-	// Cubic Bezier Functions
-
-	b3p0: function ( t, p ) {
-
-		var k = 1 - t;
-		return k * k * k * p;
-
-	},
-
-	b3p1: function ( t, p ) {
-
-		var k = 1 - t;
-		return 3 * k * k * t * p;
-
-	},
-
-	b3p2: function ( t, p ) {
-
-		var k = 1 - t;
-		return 3 * k * t * t * p;
-
-	},
-
-	b3p3: function ( t, p ) {
-
-		return t * t * t * p;
-
-	},
-
-	b3: function ( t, p0, p1, p2, p3 ) {
-
-		return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) +  this.b3p3( t, p3 );
-
-	}
-
-};
-
-/**
- * @author mikael emtinger / http://gomo.se/
- */
-
-THREE.AnimationHandler = (function() {
-
-	var playing = [];
-	var library = {};
-	var that    = {};
-
-
-	//--- update ---
-
-	that.update = function( deltaTimeMS ) {
-
-		for( var i = 0; i < playing.length; i ++ )
-			playing[ i ].update( deltaTimeMS );
-
-	};
-
-
-	//--- add ---
-
-	that.addToUpdate = function( animation ) {
-
-		if ( playing.indexOf( animation ) === -1 )
-			playing.push( animation );
-
-	};
-
-
-	//--- remove ---
-
-	that.removeFromUpdate = function( animation ) {
-
-		var index = playing.indexOf( animation );
-
-		if( index !== -1 )
-			playing.splice( index, 1 );
-
-	};
-
-
-	//--- add ---
-
-	that.add = function( data ) {
-
-		if ( library[ data.name ] !== undefined )
-			console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." );
-
-		library[ data.name ] = data;
-		initData( data );
-
-	};
-
-
-	//--- get ---
-
-	that.get = function( name ) {
-
-		if ( typeof name === "string" ) {
-
-			if ( library[ name ] ) {
-
-				return library[ name ];
-
-			} else {
-
-				console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name );
-				return null;
-
-			}
-
-		} else {
-
-			// todo: add simple tween library
-
-		}
-
-	};
-
-	//--- parse ---
-
-	that.parse = function( root ) {
-
-		// setup hierarchy
-
-		var hierarchy = [];
-
-		if ( root instanceof THREE.SkinnedMesh ) {
-
-			for( var b = 0; b < root.bones.length; b++ ) {
-
-				hierarchy.push( root.bones[ b ] );
-
-			}
-
-		} else {
-
-			parseRecurseHierarchy( root, hierarchy );
-
-		}
-
-		return hierarchy;
-
-	};
-
-	var parseRecurseHierarchy = function( root, hierarchy ) {
-
-		hierarchy.push( root );
-
-		for( var c = 0; c < root.children.length; c++ )
-			parseRecurseHierarchy( root.children[ c ], hierarchy );
-
-	}
-
-
-	//--- init data ---
-
-	var initData = function( data ) {
-
-		if( data.initialized === true )
-			return;
-
-
-		// loop through all keys
-
-		for( var h = 0; h < data.hierarchy.length; h ++ ) {
-
-			for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
-
-				// remove minus times
-
-				if( data.hierarchy[ h ].keys[ k ].time < 0 )
-					data.hierarchy[ h ].keys[ k ].time = 0;
-
-
-				// create quaternions
-
-				if( data.hierarchy[ h ].keys[ k ].rot !== undefined &&
-				 !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) {
-
-					var quat = data.hierarchy[ h ].keys[ k ].rot;
-					data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] );
-
-				}
-
-			}
-
-
-			// prepare morph target keys
-
-			if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) {
-
-				// get all used
-
-				var usedMorphTargets = {};
-
-				for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
-
-					for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
-
-						var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ];
-						usedMorphTargets[ morphTargetName ] = -1;
-
-					}
-
-				}
-
-				data.hierarchy[ h ].usedMorphTargets = usedMorphTargets;
-
-
-				// set all used on all frames
-
-				for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
-
-					var influences = {};
-
-					for ( var morphTargetName in usedMorphTargets ) {
-
-						for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
-
-							if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) {
-
-								influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ];
-								break;
-
-							}
-
-						}
-
-						if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) {
-
-							influences[ morphTargetName ] = 0;
-
-						}
-
-					}
-
-					data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences;
-
-				}
-
-			}
-
-
-			// remove all keys that are on the same time
-
-			for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) {
-
-				if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) {
-
-					data.hierarchy[ h ].keys.splice( k, 1 );
-					k --;
-
-				}
-
-			}
-
-
-			// set index
-
-			for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
-
-				data.hierarchy[ h ].keys[ k ].index = k;
-
-			}
-
-		}
-
-
-		// JIT
-
-		var lengthInFrames = parseInt( data.length * data.fps, 10 );
-
-		data.JIT = {};
-		data.JIT.hierarchy = [];
-
-		for( var h = 0; h < data.hierarchy.length; h ++ )
-			data.JIT.hierarchy.push( new Array( lengthInFrames ) );
-
-
-		// done
-
-		data.initialized = true;
-
-	};
-
-
-	// interpolation types
-
-	that.LINEAR = 0;
-	that.CATMULLROM = 1;
-	that.CATMULLROM_FORWARD = 2;
-
-	return that;
-
-}());
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Animation = function ( root, name, interpolationType ) {
-
-	this.root = root;
-	this.data = THREE.AnimationHandler.get( name );
-	this.hierarchy = THREE.AnimationHandler.parse( root );
-
-	this.currentTime = 0;
-	this.timeScale = 1;
-
-	this.isPlaying = false;
-	this.isPaused = true;
-	this.loop = true;
-
-	this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR;
-
-	this.points = [];
-	this.target = new THREE.Vector3();
-
-};
-
-THREE.Animation.prototype.play = function ( loop, startTimeMS ) {
-
-	if ( this.isPlaying === false ) {
-
-		this.isPlaying = true;
-		this.loop = loop !== undefined ? loop : true;
-		this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
-
-		// reset key cache
-
-		var h, hl = this.hierarchy.length,
-			object;
-
-		for ( h = 0; h < hl; h ++ ) {
-
-			object = this.hierarchy[ h ];
-
-			if ( this.interpolationType !== THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-				object.useQuaternion = true;
-
-			}
-
-			object.matrixAutoUpdate = true;
-
-			if ( object.animationCache === undefined ) {
-
-				object.animationCache = {};
-				object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
-				object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
-				object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
-
-			}
-
-			var prevKey = object.animationCache.prevKey;
-			var nextKey = object.animationCache.nextKey;
-
-			prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
-			prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
-			prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
-
-			nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
-			nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
-			nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
-
-		}
-
-		this.update( 0 );
-
-	}
-
-	this.isPaused = false;
-
-	THREE.AnimationHandler.addToUpdate( this );
-
-};
-
-
-THREE.Animation.prototype.pause = function() {
-
-	if ( this.isPaused === true ) {
-
-		THREE.AnimationHandler.addToUpdate( this );
-
-	} else {
-
-		THREE.AnimationHandler.removeFromUpdate( this );
-
-	}
-
-	this.isPaused = !this.isPaused;
-
-};
-
-
-THREE.Animation.prototype.stop = function() {
-
-	this.isPlaying = false;
-	this.isPaused  = false;
-	THREE.AnimationHandler.removeFromUpdate( this );
-
-};
-
-
-THREE.Animation.prototype.update = function ( deltaTimeMS ) {
-
-	// early out
-
-	if ( this.isPlaying === false ) return;
-
-
-	// vars
-
-	var types = [ "pos", "rot", "scl" ];
-	var type;
-	var scale;
-	var vector;
-	var prevXYZ, nextXYZ;
-	var prevKey, nextKey;
-	var object;
-	var animationCache;
-	var frame;
-	var JIThierarchy = this.data.JIT.hierarchy;
-	var currentTime, unloopedCurrentTime;
-	var currentPoint, forwardPoint, angle;
-
-
-	this.currentTime += deltaTimeMS * this.timeScale;
-
-	unloopedCurrentTime = this.currentTime;
-	currentTime = this.currentTime = this.currentTime % this.data.length;
-	frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
-
-
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
-
-		object = this.hierarchy[ h ];
-		animationCache = object.animationCache;
-
-		// loop through pos/rot/scl
-
-		for ( var t = 0; t < 3; t ++ ) {
-
-			// get keys
-
-			type    = types[ t ];
-			prevKey = animationCache.prevKey[ type ];
-			nextKey = animationCache.nextKey[ type ];
-
-			// switch keys?
-
-			if ( nextKey.time <= unloopedCurrentTime ) {
-
-				// did we loop?
-
-				if ( currentTime < unloopedCurrentTime ) {
-
-					if ( this.loop ) {
-
-						prevKey = this.data.hierarchy[ h ].keys[ 0 ];
-						nextKey = this.getNextKeyWith( type, h, 1 );
-
-						while( nextKey.time < currentTime ) {
-
-							prevKey = nextKey;
-							nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
-
-						}
-
-					} else {
-
-						this.stop();
-						return;
-
-					}
-
-				} else {
-
-					do {
-
-						prevKey = nextKey;
-						nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
-
-					} while( nextKey.time < currentTime )
-
-				}
-
-				animationCache.prevKey[ type ] = prevKey;
-				animationCache.nextKey[ type ] = nextKey;
-
-			}
-
-
-			object.matrixAutoUpdate = true;
-			object.matrixWorldNeedsUpdate = true;
-
-			scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
-			prevXYZ = prevKey[ type ];
-			nextXYZ = nextKey[ type ];
-
-
-			// check scale error
-
-			if ( scale < 0 || scale > 1 ) {
-
-				console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h );
-				scale = scale < 0 ? 0 : 1;
-
-			}
-
-			// interpolate
-
-			if ( type === "pos" ) {
-
-				vector = object.position;
-
-				if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
-
-					vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
-					vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
-					vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
-
-				} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-						    this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-					this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
-					this.points[ 1 ] = prevXYZ;
-					this.points[ 2 ] = nextXYZ;
-					this.points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];
-
-					scale = scale * 0.33 + 0.33;
-
-					currentPoint = this.interpolateCatmullRom( this.points, scale );
-
-					vector.x = currentPoint[ 0 ];
-					vector.y = currentPoint[ 1 ];
-					vector.z = currentPoint[ 2 ];
-
-					if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-						forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 );
-
-						this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
-						this.target.sub( vector );
-						this.target.y = 0;
-						this.target.normalize();
-
-						angle = Math.atan2( this.target.x, this.target.z );
-						object.rotation.set( 0, angle, 0 );
-
-					}
-
-				}
-
-			} else if ( type === "rot" ) {
-
-				THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );
-
-			} else if ( type === "scl" ) {
-
-				vector = object.scale;
-
-				vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
-				vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
-				vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
-
-			}
-
-		}
-
-	}
-
-};
-
-// Catmull-Rom spline
-
-THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) {
-
-	var c = [], v3 = [],
-	point, intPoint, weight, w2, w3,
-	pa, pb, pc, pd;
-
-	point = ( points.length - 1 ) * scale;
-	intPoint = Math.floor( point );
-	weight = point - intPoint;
-
-	c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
-	c[ 1 ] = intPoint;
-	c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
-	c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;
-
-	pa = points[ c[ 0 ] ];
-	pb = points[ c[ 1 ] ];
-	pc = points[ c[ 2 ] ];
-	pd = points[ c[ 3 ] ];
-
-	w2 = weight * weight;
-	w3 = weight * w2;
-
-	v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
-	v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
-	v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );
-
-	return v3;
-
-};
-
-THREE.Animation.prototype.interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
-
-	var v0 = ( p2 - p0 ) * 0.5,
-		v1 = ( p3 - p1 ) * 0.5;
-
-	return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
-
-};
-
-
-
-// Get next key with
-
-THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) {
-
-	var keys = this.data.hierarchy[ h ].keys;
-
-	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-		key = key < keys.length - 1 ? key : keys.length - 1;
-
-	} else {
-
-		key = key % keys.length;
-
-	}
-
-	for ( ; key < keys.length; key++ ) {
-
-		if ( keys[ key ][ type ] !== undefined ) {
-
-			return keys[ key ];
-
-		}
-
-	}
-
-	return this.data.hierarchy[ h ].keys[ 0 ];
-
-};
-
-// Get previous key with
-
-THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {
-
-	var keys = this.data.hierarchy[ h ].keys;
-
-	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-		key = key > 0 ? key : 0;
-
-	} else {
-
-		key = key >= 0 ? key : key + keys.length;
-
-	}
-
-
-	for ( ; key >= 0; key -- ) {
-
-		if ( keys[ key ][ type ] !== undefined ) {
-
-			return keys[ key ];
-
-		}
-
-	}
-
-	return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author khang duong
- * @author erik kitson
- */
-
-THREE.KeyFrameAnimation = function( root, data, JITCompile ) {
-
-	this.root = root;
-	this.data = THREE.AnimationHandler.get( data );
-	this.hierarchy = THREE.AnimationHandler.parse( root );
-	this.currentTime = 0;
-	this.timeScale = 0.001;
-	this.isPlaying = false;
-	this.isPaused = true;
-	this.loop = true;
-	this.JITCompile = JITCompile !== undefined ? JITCompile : true;
-
-	// initialize to first keyframes
-
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
-
-		var keys = this.data.hierarchy[h].keys,
-			sids = this.data.hierarchy[h].sids,
-			obj = this.hierarchy[h];
-
-		if ( keys.length && sids ) {
-
-			for ( var s = 0; s < sids.length; s++ ) {
-
-				var sid = sids[ s ],
-					next = this.getNextKeyWith( sid, h, 0 );
-
-				if ( next ) {
-
-					next.apply( sid );
-
-				}
-
-			}
-
-			obj.matrixAutoUpdate = false;
-			this.data.hierarchy[h].node.updateMatrix();
-			obj.matrixWorldNeedsUpdate = true;
-
-		}
-
-	}
-
-};
-
-// Play
-
-THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) {
-
-	if( !this.isPlaying ) {
-
-		this.isPlaying = true;
-		this.loop = loop !== undefined ? loop : true;
-		this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
-		this.startTimeMs = startTimeMS;
-		this.startTime = 10000000;
-		this.endTime = -this.startTime;
-
-
-		// reset key cache
-
-		var h, hl = this.hierarchy.length,
-			object,
-			node;
-
-		for ( h = 0; h < hl; h++ ) {
-
-			object = this.hierarchy[ h ];
-			node = this.data.hierarchy[ h ];
-			object.useQuaternion = true;
-
-			if ( node.animationCache === undefined ) {
-
-				node.animationCache = {};
-				node.animationCache.prevKey = null;
-				node.animationCache.nextKey = null;
-				node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
-
-			}
-
-			var keys = this.data.hierarchy[h].keys;
-
-			if (keys.length) {
-
-				node.animationCache.prevKey = keys[ 0 ];
-				node.animationCache.nextKey = keys[ 1 ];
-
-				this.startTime = Math.min( keys[0].time, this.startTime );
-				this.endTime = Math.max( keys[keys.length - 1].time, this.endTime );
-
-			}
-
-		}
-
-		this.update( 0 );
-
-	}
-
-	this.isPaused = false;
-
-	THREE.AnimationHandler.addToUpdate( this );
-
-};
-
-
-
-// Pause
-
-THREE.KeyFrameAnimation.prototype.pause = function() {
-
-	if( this.isPaused ) {
-
-		THREE.AnimationHandler.addToUpdate( this );
-
-	} else {
-
-		THREE.AnimationHandler.removeFromUpdate( this );
-
-	}
-
-	this.isPaused = !this.isPaused;
-
-};
-
-
-// Stop
-
-THREE.KeyFrameAnimation.prototype.stop = function() {
-
-	this.isPlaying = false;
-	this.isPaused  = false;
-	THREE.AnimationHandler.removeFromUpdate( this );
-
-
-	// reset JIT matrix and remove cache
-
-	for ( var h = 0; h < this.data.hierarchy.length; h++ ) {
-        
-        var obj = this.hierarchy[ h ];
-		var node = this.data.hierarchy[ h ];
-
-		if ( node.animationCache !== undefined ) {
-
-			var original = node.animationCache.originalMatrix;
-
-			if( obj instanceof THREE.Bone ) {
-
-				original.copy( obj.skinMatrix );
-				obj.skinMatrix = original;
-
-			} else {
-
-				original.copy( obj.matrix );
-				obj.matrix = original;
-
-			}
-
-			delete node.animationCache;
-
-		}
-
-	}
-
-};
-
-
-// Update
-
-THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) {
-
-	// early out
-
-	if( !this.isPlaying ) return;
-
-
-	// vars
-
-	var prevKey, nextKey;
-	var object;
-	var node;
-	var frame;
-	var JIThierarchy = this.data.JIT.hierarchy;
-	var currentTime, unloopedCurrentTime;
-	var looped;
-
-
-	// update
-
-	this.currentTime += deltaTimeMS * this.timeScale;
-
-	unloopedCurrentTime = this.currentTime;
-	currentTime         = this.currentTime = this.currentTime % this.data.length;
-
-	// if looped around, the current time should be based on the startTime
-	if ( currentTime < this.startTimeMs ) {
-
-		currentTime = this.currentTime = this.startTimeMs + currentTime;
-
-	}
-
-	frame               = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
-	looped 				= currentTime < unloopedCurrentTime;
-
-	if ( looped && !this.loop ) {
-
-		// Set the animation to the last keyframes and stop
-		for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
-
-			var keys = this.data.hierarchy[h].keys,
-				sids = this.data.hierarchy[h].sids,
-				end = keys.length-1,
-				obj = this.hierarchy[h];
-
-			if ( keys.length ) {
-
-				for ( var s = 0; s < sids.length; s++ ) {
-
-					var sid = sids[ s ],
-						prev = this.getPrevKeyWith( sid, h, end );
-
-					if ( prev ) {
-						prev.apply( sid );
-
-					}
-
-				}
-
-				this.data.hierarchy[h].node.updateMatrix();
-				obj.matrixWorldNeedsUpdate = true;
-
-			}
-
-		}
-
-		this.stop();
-		return;
-
-	}
-
-	// check pre-infinity
-	if ( currentTime < this.startTime ) {
-
-		return;
-
-	}
-
-	// update
-
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
-
-		object = this.hierarchy[ h ];
-		node = this.data.hierarchy[ h ];
-
-		var keys = node.keys,
-			animationCache = node.animationCache;
-
-		// use JIT?
-
-		if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) {
-
-			if( object instanceof THREE.Bone ) {
-
-				object.skinMatrix = JIThierarchy[ h ][ frame ];
-				object.matrixWorldNeedsUpdate = false;
-
-			} else {
-
-				object.matrix = JIThierarchy[ h ][ frame ];
-				object.matrixWorldNeedsUpdate = true;
-
-			}
-
-		// use interpolation
-
-		} else if ( keys.length ) {
-
-			// make sure so original matrix and not JIT matrix is set
-
-			if ( this.JITCompile && animationCache ) {
-
-				if( object instanceof THREE.Bone ) {
-
-					object.skinMatrix = animationCache.originalMatrix;
-
-				} else {
-
-					object.matrix = animationCache.originalMatrix;
-
-				}
-
-			}
-
-			prevKey = animationCache.prevKey;
-			nextKey = animationCache.nextKey;
-
-			if ( prevKey && nextKey ) {
-
-				// switch keys?
-
-				if ( nextKey.time <= unloopedCurrentTime ) {
-
-					// did we loop?
-
-					if ( looped && this.loop ) {
-
-						prevKey = keys[ 0 ];
-						nextKey = keys[ 1 ];
-
-						while ( nextKey.time < currentTime ) {
-
-							prevKey = nextKey;
-							nextKey = keys[ prevKey.index + 1 ];
-
-						}
-
-					} else if ( !looped ) {
-
-						var lastIndex = keys.length - 1;
-
-						while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) {
-
-							prevKey = nextKey;
-							nextKey = keys[ prevKey.index + 1 ];
-
-						}
-
-					}
-
-					animationCache.prevKey = prevKey;
-					animationCache.nextKey = nextKey;
-
-				}
-                if(nextKey.time >= currentTime)
-                    prevKey.interpolate( nextKey, currentTime );
-                else
-                    prevKey.interpolate( nextKey, nextKey.time);
-
-			}
-
-			this.data.hierarchy[h].node.updateMatrix();
-			object.matrixWorldNeedsUpdate = true;
-
-		}
-
-	}
-
-	// update JIT?
-
-	if ( this.JITCompile ) {
-
-		if ( JIThierarchy[ 0 ][ frame ] === undefined ) {
-
-			this.hierarchy[ 0 ].updateMatrixWorld( true );
-
-			for ( var h = 0; h < this.hierarchy.length; h++ ) {
-
-				if( this.hierarchy[ h ] instanceof THREE.Bone ) {
-
-					JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();
-
-				} else {
-
-					JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone();
-
-				}
-
-			}
-
-		}
-
-	}
-
-};
-
-// Get next key with
-
-THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) {
-
-	var keys = this.data.hierarchy[ h ].keys;
-	key = key % keys.length;
-
-	for ( ; key < keys.length; key++ ) {
-
-		if ( keys[ key ].hasTarget( sid ) ) {
-
-			return keys[ key ];
-
-		}
-
-	}
-
-	return keys[ 0 ];
-
-};
-
-// Get previous key with
-
-THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) {
-
-	var keys = this.data.hierarchy[ h ].keys;
-	key = key >= 0 ? key : key + keys.length;
-
-	for ( ; key >= 0; key-- ) {
-
-		if ( keys[ key ].hasTarget( sid ) ) {
-
-			return keys[ key ];
-
-		}
-
-	}
-
-	return keys[ keys.length - 1 ];
-
-};
-/**
- * Camera for rendering cube maps
- *	- renders scene into axis-aligned cube
- *
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.CubeCamera = function ( near, far, cubeResolution ) {
-
-	THREE.Object3D.call( this );
-
-	var fov = 90, aspect = 1;
-
-	var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraPX.up.set( 0, -1, 0 );
-	cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) );
-	this.add( cameraPX );
-
-	var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraNX.up.set( 0, -1, 0 );
-	cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) );
-	this.add( cameraNX );
-
-	var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraPY.up.set( 0, 0, 1 );
-	cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) );
-	this.add( cameraPY );
-
-	var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraNY.up.set( 0, 0, -1 );
-	cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) );
-	this.add( cameraNY );
-
-	var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraPZ.up.set( 0, -1, 0 );
-	cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) );
-	this.add( cameraPZ );
-
-	var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	cameraNZ.up.set( 0, -1, 0 );
-	cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) );
-	this.add( cameraNZ );
-
-	this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
-
-	this.updateCubeMap = function ( renderer, scene ) {
-
-		var renderTarget = this.renderTarget;
-		var generateMipmaps = renderTarget.generateMipmaps;
-
-		renderTarget.generateMipmaps = false;
-
-		renderTarget.activeCubeFace = 0;
-		renderer.render( scene, cameraPX, renderTarget );
-
-		renderTarget.activeCubeFace = 1;
-		renderer.render( scene, cameraNX, renderTarget );
-
-		renderTarget.activeCubeFace = 2;
-		renderer.render( scene, cameraPY, renderTarget );
-
-		renderTarget.activeCubeFace = 3;
-		renderer.render( scene, cameraNY, renderTarget );
-
-		renderTarget.activeCubeFace = 4;
-		renderer.render( scene, cameraPZ, renderTarget );
-
-		renderTarget.generateMipmaps = generateMipmaps;
-
-		renderTarget.activeCubeFace = 5;
-		renderer.render( scene, cameraNZ, renderTarget );
-
-	};
-
-};
-
-THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype );
-/*
- *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
- *
- *	A general perpose camera, for setting FOV, Lens Focal Length,
- *		and switching between perspective and orthographic views easily.
- *		Use this only if you do not wish to manage
- *		both a Orthographic and Perspective Camera
- *
- */
-
-
-THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) {
-
-	THREE.Camera.call( this );
-
-	this.fov = fov;
-
-	this.left = -width / 2;
-	this.right = width / 2
-	this.top = height / 2;
-	this.bottom = -height / 2;
-
-	// We could also handle the projectionMatrix internally, but just wanted to test nested camera objects
-
-	this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 	orthoNear, orthoFar );
-	this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far );
-
-	this.zoom = 1;
-
-	this.toPerspective();
-
-	var aspect = width/height;
-
-};
-
-THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype );
-
-THREE.CombinedCamera.prototype.toPerspective = function () {
-
-	// Switches to the Perspective Camera
-
-	this.near = this.cameraP.near;
-	this.far = this.cameraP.far;
-
-	this.cameraP.fov =  this.fov / this.zoom ;
-
-	this.cameraP.updateProjectionMatrix();
-
-	this.projectionMatrix = this.cameraP.projectionMatrix;
-
-	this.inPerspectiveMode = true;
-	this.inOrthographicMode = false;
-
-};
-
-THREE.CombinedCamera.prototype.toOrthographic = function () {
-
-	// Switches to the Orthographic camera estimating viewport from Perspective
-
-	var fov = this.fov;
-	var aspect = this.cameraP.aspect;
-	var near = this.cameraP.near;
-	var far = this.cameraP.far;
-
-	// The size that we set is the mid plane of the viewing frustum
-
-	var hyperfocus = ( near + far ) / 2;
-
-	var halfHeight = Math.tan( fov / 2 ) * hyperfocus;
-	var planeHeight = 2 * halfHeight;
-	var planeWidth = planeHeight * aspect;
-	var halfWidth = planeWidth / 2;
-
-	halfHeight /= this.zoom;
-	halfWidth /= this.zoom;
-
-	this.cameraO.left = -halfWidth;
-	this.cameraO.right = halfWidth;
-	this.cameraO.top = halfHeight;
-	this.cameraO.bottom = -halfHeight;
-
-	// this.cameraO.left = -farHalfWidth;
-	// this.cameraO.right = farHalfWidth;
-	// this.cameraO.top = farHalfHeight;
-	// this.cameraO.bottom = -farHalfHeight;
-
-	// this.cameraO.left = this.left / this.zoom;
-	// this.cameraO.right = this.right / this.zoom;
-	// this.cameraO.top = this.top / this.zoom;
-	// this.cameraO.bottom = this.bottom / this.zoom;
-
-	this.cameraO.updateProjectionMatrix();
-
-	this.near = this.cameraO.near;
-	this.far = this.cameraO.far;
-	this.projectionMatrix = this.cameraO.projectionMatrix;
-
-	this.inPerspectiveMode = false;
-	this.inOrthographicMode = true;
-
-};
-
-
-THREE.CombinedCamera.prototype.setSize = function( width, height ) {
-
-	this.cameraP.aspect = width / height;
-	this.left = -width / 2;
-	this.right = width / 2
-	this.top = height / 2;
-	this.bottom = -height / 2;
-
-};
-
-
-THREE.CombinedCamera.prototype.setFov = function( fov ) {
-
-	this.fov = fov;
-
-	if ( this.inPerspectiveMode ) {
-
-		this.toPerspective();
-
-	} else {
-
-		this.toOrthographic();
-
-	}
-
-};
-
-// For mantaining similar API with PerspectiveCamera
-
-THREE.CombinedCamera.prototype.updateProjectionMatrix = function() {
-
-	if ( this.inPerspectiveMode ) {
-
-		this.toPerspective();
-
-	} else {
-
-		this.toPerspective();
-		this.toOrthographic();
-
-	}
-
-};
-
-/*
-* Uses Focal Length (in mm) to estimate and set FOV
-* 35mm (fullframe) camera is used if frame size is not specified;
-* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
-*/
-THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) {
-
-	if ( frameHeight === undefined ) frameHeight = 24;
-
-	var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
-
-	this.setFov( fov );
-
-	return fov;
-};
-
-
-THREE.CombinedCamera.prototype.setZoom = function( zoom ) {
-
-	this.zoom = zoom;
-
-	if ( this.inPerspectiveMode ) {
-
-		this.toPerspective();
-
-	} else {
-
-		this.toOrthographic();
-
-	}
-
-};
-
-THREE.CombinedCamera.prototype.toFrontView = function() {
-
-	this.rotation.x = 0;
-	this.rotation.y = 0;
-	this.rotation.z = 0;
-
-	// should we be modifing the matrix instead?
-
-	this.rotationAutoUpdate = false;
-
-};
-
-THREE.CombinedCamera.prototype.toBackView = function() {
-
-	this.rotation.x = 0;
-	this.rotation.y = Math.PI;
-	this.rotation.z = 0;
-	this.rotationAutoUpdate = false;
-
-};
-
-THREE.CombinedCamera.prototype.toLeftView = function() {
-
-	this.rotation.x = 0;
-	this.rotation.y = - Math.PI / 2;
-	this.rotation.z = 0;
-	this.rotationAutoUpdate = false;
-
-};
-
-THREE.CombinedCamera.prototype.toRightView = function() {
-
-	this.rotation.x = 0;
-	this.rotation.y = Math.PI / 2;
-	this.rotation.z = 0;
-	this.rotationAutoUpdate = false;
-
-};
-
-THREE.CombinedCamera.prototype.toTopView = function() {
-
-	this.rotation.x = - Math.PI / 2;
-	this.rotation.y = 0;
-	this.rotation.z = 0;
-	this.rotationAutoUpdate = false;
-
-};
-
-THREE.CombinedCamera.prototype.toBottomView = function() {
-
-	this.rotation.x = Math.PI / 2;
-	this.rotation.y = 0;
-	this.rotation.z = 0;
-	this.rotationAutoUpdate = false;
-
-};
-
-/**
- * @author hughes
- */
-
-THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {
-
-	THREE.Geometry.call( this );
-
-	radius = radius || 50;
-
-	thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
-	segments = segments !== undefined ? Math.max( 3, segments ) : 8;
-
-	var i, uvs = [],
-	center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 );
-
-	this.vertices.push(center);
-	uvs.push( centerUV );
-
-	for ( i = 0; i <= segments; i ++ ) {
-
-		var vertex = new THREE.Vector3();
-		var segment = thetaStart + i / segments * thetaLength;
-
-		vertex.x = radius * Math.cos( segment );
-		vertex.y = radius * Math.sin( segment );
-
-		this.vertices.push( vertex );
-		uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) );
-
-	}
-
-	var n = new THREE.Vector3( 0, 0, 1 );
-
-	for ( i = 1; i <= segments; i ++ ) {
-
-		var v1 = i;
-		var v2 = i + 1 ;
-		var v3 = 0;
-
-		this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) );
-		this.faceVertexUvs[ 0 ].push( [ uvs[ i ], uvs[ i + 1 ], centerUV ] );
-
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
-
-};
-
-THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author mrdoob / http://mrdoob.com/
- * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
- */
-
-THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
-
-	THREE.Geometry.call( this );
-
-	var scope = this;
-
-	this.width = width;
-	this.height = height;
-	this.depth = depth;
-
-	this.widthSegments = widthSegments || 1;
-	this.heightSegments = heightSegments || 1;
-	this.depthSegments = depthSegments || 1;
-
-	var width_half = this.width / 2;
-	var height_half = this.height / 2;
-	var depth_half = this.depth / 2;
-
-	buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px
-	buildPlane( 'z', 'y',   1, - 1, this.depth, this.height, - width_half, 1 ); // nx
-	buildPlane( 'x', 'z',   1,   1, this.width, this.depth, height_half, 2 ); // py
-	buildPlane( 'x', 'z',   1, - 1, this.width, this.depth, - height_half, 3 ); // ny
-	buildPlane( 'x', 'y',   1, - 1, this.width, this.height, depth_half, 4 ); // pz
-	buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz
-
-	function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) {
-
-		var w, ix, iy,
-		gridX = scope.widthSegments,
-		gridY = scope.heightSegments,
-		width_half = width / 2,
-		height_half = height / 2,
-		offset = scope.vertices.length;
-
-		if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {
-
-			w = 'z';
-
-		} else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {
-
-			w = 'y';
-			gridY = scope.depthSegments;
-
-		} else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {
-
-			w = 'x';
-			gridX = scope.depthSegments;
-
-		}
-
-		var gridX1 = gridX + 1,
-		gridY1 = gridY + 1,
-		segment_width = width / gridX,
-		segment_height = height / gridY,
-		normal = new THREE.Vector3();
-
-		normal[ w ] = depth > 0 ? 1 : - 1;
-
-		for ( iy = 0; iy < gridY1; iy ++ ) {
-
-			for ( ix = 0; ix < gridX1; ix ++ ) {
-
-				var vector = new THREE.Vector3();
-				vector[ u ] = ( ix * segment_width - width_half ) * udir;
-				vector[ v ] = ( iy * segment_height - height_half ) * vdir;
-				vector[ w ] = depth;
-
-				scope.vertices.push( vector );
-
-			}
-
-		}
-
-		for ( iy = 0; iy < gridY; iy++ ) {
-
-			for ( ix = 0; ix < gridX; ix++ ) {
-
-				var a = ix + gridX1 * iy;
-				var b = ix + gridX1 * ( iy + 1 );
-				var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
-				var d = ( ix + 1 ) + gridX1 * iy;
-
-				var face = new THREE.Face4( a + offset, b + offset, c + offset, d + offset );
-				face.normal.copy( normal );
-				face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );
-				face.materialIndex = materialIndex;
-
-				scope.faces.push( face );
-				scope.faceVertexUvs[ 0 ].push( [
-							new THREE.Vector2( ix / gridX, 1 - iy / gridY ),
-							new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ),
-							new THREE.Vector2( ( ix + 1 ) / gridX, 1- ( iy + 1 ) / gridY ),
-							new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY )
-						] );
-
-			}
-
-		}
-
-	}
-
-	this.computeCentroids();
-	this.mergeVertices();
-
-};
-
-THREE.CubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded ) {
-
-	THREE.Geometry.call( this );
-
-	this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20;
-	this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
-	this.height = height = height !== undefined ? height : 100;
-
-	this.radiusSegments = radiusSegments = radiusSegments || 8;
-	this.heightSegments = heightSegments = heightSegments || 1;
-
-	this.openEnded = openEnded = openEnded !== undefined ? openEnded : false;
-
-	var heightHalf = height / 2;
-
-	var x, y, vertices = [], uvs = [];
-
-	for ( y = 0; y <= heightSegments; y ++ ) {
-
-		var verticesRow = [];
-		var uvsRow = [];
-
-		var v = y / heightSegments;
-		var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
-
-		for ( x = 0; x <= radiusSegments; x ++ ) {
-
-			var u = x / radiusSegments;
-
-			var vertex = new THREE.Vector3();
-			vertex.x = radius * Math.sin( u * Math.PI * 2 );
-			vertex.y = - v * height + heightHalf;
-			vertex.z = radius * Math.cos( u * Math.PI * 2 );
-
-			this.vertices.push( vertex );
-
-			verticesRow.push( this.vertices.length - 1 );
-			uvsRow.push( new THREE.Vector2( u, 1 - v ) );
-
-		}
-
-		vertices.push( verticesRow );
-		uvs.push( uvsRow );
-
-	}
-
-	var tanTheta = ( radiusBottom - radiusTop ) / height;
-	var na, nb;
-
-	for ( x = 0; x < radiusSegments; x ++ ) {
-
-		if ( radiusTop !== 0 ) {
-
-			na = this.vertices[ vertices[ 0 ][ x ] ].clone();
-			nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone();
-
-		} else {
-
-			na = this.vertices[ vertices[ 1 ][ x ] ].clone();
-			nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone();
-
-		}
-
-		na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize();
-		nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize();
-
-		for ( y = 0; y < heightSegments; y ++ ) {
-
-			var v1 = vertices[ y ][ x ];
-			var v2 = vertices[ y + 1 ][ x ];
-			var v3 = vertices[ y + 1 ][ x + 1 ];
-			var v4 = vertices[ y ][ x + 1 ];
-
-			var n1 = na.clone();
-			var n2 = na.clone();
-			var n3 = nb.clone();
-			var n4 = nb.clone();
-
-			var uv1 = uvs[ y ][ x ].clone();
-			var uv2 = uvs[ y + 1 ][ x ].clone();
-			var uv3 = uvs[ y + 1 ][ x + 1 ].clone();
-			var uv4 = uvs[ y ][ x + 1 ].clone();
-
-			this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
-			this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );
-
-		}
-
-	}
-
-	// top cap
-
-	if ( openEnded === false && radiusTop > 0 ) {
-
-		this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );
-
-		for ( x = 0; x < radiusSegments; x ++ ) {
-
-			var v1 = vertices[ 0 ][ x ];
-			var v2 = vertices[ 0 ][ x + 1 ];
-			var v3 = this.vertices.length - 1;
-
-			var n1 = new THREE.Vector3( 0, 1, 0 );
-			var n2 = new THREE.Vector3( 0, 1, 0 );
-			var n3 = new THREE.Vector3( 0, 1, 0 );
-
-			var uv1 = uvs[ 0 ][ x ].clone();
-			var uv2 = uvs[ 0 ][ x + 1 ].clone();
-			var uv3 = new THREE.Vector2( uv2.u, 0 );
-
-			this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
-			this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
-
-		}
-
-	}
-
-	// bottom cap
-
-	if ( openEnded === false && radiusBottom > 0 ) {
-
-		this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) );
-
-		for ( x = 0; x < radiusSegments; x ++ ) {
-
-			var v1 = vertices[ y ][ x + 1 ];
-			var v2 = vertices[ y ][ x ];
-			var v3 = this.vertices.length - 1;
-
-			var n1 = new THREE.Vector3( 0, - 1, 0 );
-			var n2 = new THREE.Vector3( 0, - 1, 0 );
-			var n3 = new THREE.Vector3( 0, - 1, 0 );
-
-			var uv1 = uvs[ y ][ x + 1 ].clone();
-			var uv2 = uvs[ y ][ x ].clone();
-			var uv3 = new THREE.Vector2( uv2.u, 1 );
-
-			this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
-			this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
-
-		}
-
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-}
-
-THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- * Creates extruded geometry from a path shape.
- *
- * parameters = {
- *
- *  size: <float>, // size of the text
- *  height: <float>, // thickness to extrude text
- *  curveSegments: <int>, // number of points on the curves
- *  steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too
- *  amount: <int>, // Amount
- *
- *  bevelEnabled: <bool>, // turn on bevel
- *  bevelThickness: <float>, // how deep into text bevel goes
- *  bevelSize: <float>, // how far from text outline is bevel
- *  bevelSegments: <int>, // number of bevel layers
- *
- *  extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined)
- *  frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals
- *
- *  material: <int> // material index for front and back faces
- *  extrudeMaterial: <int> // material index for extrusion and beveled faces
- *  uvGenerator: <Object> // object that provides UV generator functions
- *
- * }
- **/
-
-THREE.ExtrudeGeometry = function ( shapes, options ) {
-
-	if ( typeof( shapes ) === "undefined" ) {
-		shapes = [];
-		return;
-	}
-
-	THREE.Geometry.call( this );
-
-	shapes = shapes instanceof Array ? shapes : [ shapes ];
-
-	this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox();
-
-	this.addShapeList( shapes, options );
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-	// can't really use automatic vertex normals
-	// as then front and back sides get smoothed too
-	// should do separate smoothing just for sides
-
-	//this.computeVertexNormals();
-
-	//console.log( "took", ( Date.now() - startTime ) );
-
-};
-
-THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype );
-
-THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) {
-	var sl = shapes.length;
-
-	for ( var s = 0; s < sl; s ++ ) {
-		var shape = shapes[ s ];
-		this.addShape( shape, options );
-	}
-};
-
-THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) {
-
-	var amount = options.amount !== undefined ? options.amount : 100;
-
-	var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10
-	var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8
-	var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
-
-	var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false
-
-	var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
-
-	var steps = options.steps !== undefined ? options.steps : 1;
-
-	var extrudePath = options.extrudePath;
-	var extrudePts, extrudeByPath = false;
-
-	var material = options.material;
-	var extrudeMaterial = options.extrudeMaterial;
-
-	// Use default WorldUVGenerator if no UV generators are specified.
-	var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator;
-
-	var shapebb = this.shapebb;
-	//shapebb = shape.getBoundingBox();
-
-
-
-	var splineTube, binormal, normal, position2;
-	if ( extrudePath ) {
-
-		extrudePts = extrudePath.getSpacedPoints( steps );
-
-		extrudeByPath = true;
-		bevelEnabled = false; // bevels not supported for path extrusion
-
-		// SETUP TNB variables
-
-		// Reuse TNB from TubeGeomtry for now.
-		// TODO1 - have a .isClosed in spline?
-
-		splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false);
-
-		// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
-
-		binormal = new THREE.Vector3();
-		normal = new THREE.Vector3();
-		position2 = new THREE.Vector3();
-
-	}
-
-	// Safeguards if bevels are not enabled
-
-	if ( ! bevelEnabled ) {
-
-		bevelSegments = 0;
-		bevelThickness = 0;
-		bevelSize = 0;
-
-	}
-
-	// Variables initalization
-
-	var ahole, h, hl; // looping of holes
-	var scope = this;
-	var bevelPoints = [];
-
-	var shapesOffset = this.vertices.length;
-
-	var shapePoints = shape.extractPoints( curveSegments );
-
-	var vertices = shapePoints.shape;
-	var holes = shapePoints.holes;
-
-	var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ;
-
-	if ( reverse ) {
-
-		vertices = vertices.reverse();
-
-		// Maybe we should also check if holes are in the opposite direction, just to be safe ...
-
-		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
-
-			ahole = holes[ h ];
-
-			if ( THREE.Shape.Utils.isClockWise( ahole ) ) {
-
-				holes[ h ] = ahole.reverse();
-
-			}
-
-		}
-
-		reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)!
-
-	}
-
-
-	var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes );
-
-	/* Vertices */
-
-	var contour = vertices; // vertices has all points but contour has only points of circumference
-
-	for ( h = 0, hl = holes.length;  h < hl; h ++ ) {
-
-		ahole = holes[ h ];
-
-		vertices = vertices.concat( ahole );
-
-	}
-
-
-	function scalePt2 ( pt, vec, size ) {
-
-		if ( !vec ) console.log( "die" );
-
-		return vec.clone().multiplyScalar( size ).add( pt );
-
-	}
-
-	var b, bs, t, z,
-		vert, vlen = vertices.length,
-		face, flen = faces.length,
-		cont, clen = contour.length;
-
-
-	// Find directions for point movement
-
-	var RAD_TO_DEGREES = 180 / Math.PI;
-
-
-	function getBevelVec( pt_i, pt_j, pt_k ) {
-
-		// Algorithm 2
-
-		return getBevelVec2( pt_i, pt_j, pt_k );
-
-	}
-
-	function getBevelVec1( pt_i, pt_j, pt_k ) {
-
-		var anglea = Math.atan2( pt_j.y - pt_i.y, pt_j.x - pt_i.x );
-		var angleb = Math.atan2( pt_k.y - pt_i.y, pt_k.x - pt_i.x );
-
-		if ( anglea > angleb ) {
-
-			angleb += Math.PI * 2;
-
-		}
-
-		var anglec = ( anglea + angleb ) / 2;
-
-
-		//console.log('angle1', anglea * RAD_TO_DEGREES,'angle2', angleb * RAD_TO_DEGREES, 'anglec', anglec *RAD_TO_DEGREES);
-
-		var x = - Math.cos( anglec );
-		var y = - Math.sin( anglec );
-
-		var vec = new THREE.Vector2( x, y ); //.normalize();
-
-		return vec;
-
-	}
-
-	function getBevelVec2( pt_i, pt_j, pt_k ) {
-
-		var a = THREE.ExtrudeGeometry.__v1,
-			b = THREE.ExtrudeGeometry.__v2,
-			v_hat = THREE.ExtrudeGeometry.__v3,
-			w_hat = THREE.ExtrudeGeometry.__v4,
-			p = THREE.ExtrudeGeometry.__v5,
-			q = THREE.ExtrudeGeometry.__v6,
-			v, w,
-			v_dot_w_hat, q_sub_p_dot_w_hat,
-			s, intersection;
-
-		// good reading for line-line intersection
-		// http://sputsoft.com/blog/2010/03/line-line-intersection.html
-
-		// define a as vector j->i
-		// define b as vectot k->i
-
-		a.set( pt_i.x - pt_j.x, pt_i.y - pt_j.y );
-		b.set( pt_i.x - pt_k.x, pt_i.y - pt_k.y );
-
-		// get unit vectors
-
-		v = a.normalize();
-		w = b.normalize();
-
-		// normals from pt i
-
-		v_hat.set( -v.y, v.x );
-		w_hat.set( w.y, -w.x );
-
-		// pts from i
-
-		p.copy( pt_i ).add( v_hat );
-		q.copy( pt_i ).add( w_hat );
-
-		if ( p.equals( q ) ) {
-
-			//console.log("Warning: lines are straight");
-			return w_hat.clone();
-
-		}
-
-		// Points from j, k. helps prevents points cross overover most of the time
-
-		p.copy( pt_j ).add( v_hat );
-		q.copy( pt_k ).add( w_hat );
-
-		v_dot_w_hat = v.dot( w_hat );
-		q_sub_p_dot_w_hat = q.sub( p ).dot( w_hat );
-
-		// We should not reach these conditions
-
-		if ( v_dot_w_hat === 0 ) {
-
-			console.log( "Either infinite or no solutions!" );
-
-			if ( q_sub_p_dot_w_hat === 0 ) {
-
-				console.log( "Its finite solutions." );
-
-			} else {
-
-				console.log( "Too bad, no solutions." );
-
-			}
-
-		}
-
-		s = q_sub_p_dot_w_hat / v_dot_w_hat;
-
-		if ( s < 0 ) {
-
-			// in case of emergecy, revert to algorithm 1.
-
-			return getBevelVec1( pt_i, pt_j, pt_k );
-
-		}
-
-		intersection = v.multiplyScalar( s ).add( p );
-
-		return intersection.sub( pt_i ).clone(); // Don't normalize!, otherwise sharp corners become ugly
-
-	}
-
-	var contourMovements = [];
-
-	for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
-
-		if ( j === il ) j = 0;
-		if ( k === il ) k = 0;
-
-		//  (j)---(i)---(k)
-		// console.log('i,j,k', i, j , k)
-
-		var pt_i = contour[ i ];
-		var pt_j = contour[ j ];
-		var pt_k = contour[ k ];
-
-		contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
-
-	}
-
-	var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat();
-
-	for ( h = 0, hl = holes.length; h < hl; h ++ ) {
-
-		ahole = holes[ h ];
-
-		oneHoleMovements = [];
-
-		for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
-
-			if ( j === il ) j = 0;
-			if ( k === il ) k = 0;
-
-			//  (j)---(i)---(k)
-			oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
-
-		}
-
-		holesMovements.push( oneHoleMovements );
-		verticesMovements = verticesMovements.concat( oneHoleMovements );
-
-	}
-
-
-	// Loop bevelSegments, 1 for the front, 1 for the back
-
-	for ( b = 0; b < bevelSegments; b ++ ) {
-	//for ( b = bevelSegments; b > 0; b -- ) {
-
-		t = b / bevelSegments;
-		z = bevelThickness * ( 1 - t );
-
-		//z = bevelThickness * t;
-		bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved
-		//bs = bevelSize * t ; // linear
-
-		// contract shape
-
-		for ( i = 0, il = contour.length; i < il; i ++ ) {
-
-			vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
-			//vert = scalePt( contour[ i ], contourCentroid, bs, false );
-			v( vert.x, vert.y,  - z );
-
-		}
-
-		// expand holes
-
-		for ( h = 0, hl = holes.length; h < hl; h++ ) {
-
-			ahole = holes[ h ];
-			oneHoleMovements = holesMovements[ h ];
-
-			for ( i = 0, il = ahole.length; i < il; i++ ) {
-
-				vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
-				//vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true );
-
-				v( vert.x, vert.y,  -z );
-
-			}
-
-		}
-
-	}
-
-	bs = bevelSize;
-
-	// Back facing vertices
-
-	for ( i = 0; i < vlen; i ++ ) {
-
-		vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
-
-		if ( !extrudeByPath ) {
-
-			v( vert.x, vert.y, 0 );
-
-		} else {
-
-			// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
-
-			normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x);
-			binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y);
-
-			position2.copy( extrudePts[0] ).add(normal).add(binormal);
-
-			v( position2.x, position2.y, position2.z );
-
-		}
-
-	}
-
-	// Add stepped vertices...
-	// Including front facing vertices
-
-	var s;
-
-	for ( s = 1; s <= steps; s ++ ) {
-
-		for ( i = 0; i < vlen; i ++ ) {
-
-			vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
-
-			if ( !extrudeByPath ) {
-
-				v( vert.x, vert.y, amount / steps * s );
-
-			} else {
-
-				// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
-
-				normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x );
-				binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y );
-
-				position2.copy( extrudePts[s] ).add( normal ).add( binormal );
-
-				v( position2.x, position2.y, position2.z );
-
-			}
-
-		}
-
-	}
-
-
-	// Add bevel segments planes
-
-	//for ( b = 1; b <= bevelSegments; b ++ ) {
-	for ( b = bevelSegments - 1; b >= 0; b -- ) {
-
-		t = b / bevelSegments;
-		z = bevelThickness * ( 1 - t );
-		//bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) );
-		bs = bevelSize * Math.sin ( t * Math.PI/2 ) ;
-
-		// contract shape
-
-		for ( i = 0, il = contour.length; i < il; i ++ ) {
-
-			vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
-			v( vert.x, vert.y,  amount + z );
-
-		}
-
-		// expand holes
-
-		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
-
-			ahole = holes[ h ];
-			oneHoleMovements = holesMovements[ h ];
-
-			for ( i = 0, il = ahole.length; i < il; i ++ ) {
-
-				vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
-
-				if ( !extrudeByPath ) {
-
-					v( vert.x, vert.y,  amount + z );
-
-				} else {
-
-					v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
-
-				}
-
-			}
-
-		}
-
-	}
-
-	/* Faces */
-
-	// Top and bottom faces
-
-	buildLidFaces();
-
-	// Sides faces
-
-	buildSideFaces();
-
-
-	/////  Internal functions
-
-	function buildLidFaces() {
-
-		if ( bevelEnabled ) {
-
-			var layer = 0 ; // steps + 1
-			var offset = vlen * layer;
-
-			// Bottom faces
-
-			for ( i = 0; i < flen; i ++ ) {
-
-				face = faces[ i ];
-				f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true );
-
-			}
-
-			layer = steps + bevelSegments * 2;
-			offset = vlen * layer;
-
-			// Top faces
-
-			for ( i = 0; i < flen; i ++ ) {
-
-				face = faces[ i ];
-				f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false );
-
-			}
-
-		} else {
-
-			// Bottom faces
-
-			for ( i = 0; i < flen; i++ ) {
-
-				face = faces[ i ];
-				f3( face[ 2 ], face[ 1 ], face[ 0 ], true );
-
-			}
-
-			// Top faces
-
-			for ( i = 0; i < flen; i ++ ) {
-
-				face = faces[ i ];
-				f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false );
-
-			}
-		}
-
-	}
-
-	// Create faces for the z-sides of the shape
-
-	function buildSideFaces() {
-
-		var layeroffset = 0;
-		sidewalls( contour, layeroffset );
-		layeroffset += contour.length;
-
-		for ( h = 0, hl = holes.length;  h < hl; h ++ ) {
-
-			ahole = holes[ h ];
-			sidewalls( ahole, layeroffset );
-
-			//, true
-			layeroffset += ahole.length;
-
-		}
-
-	}
-
-	function sidewalls( contour, layeroffset ) {
-
-		var j, k;
-		i = contour.length;
-
-		while ( --i >= 0 ) {
-
-			j = i;
-			k = i - 1;
-			if ( k < 0 ) k = contour.length - 1;
-
-			//console.log('b', i,j, i-1, k,vertices.length);
-
-			var s = 0, sl = steps  + bevelSegments * 2;
-
-			for ( s = 0; s < sl; s ++ ) {
-
-				var slen1 = vlen * s;
-				var slen2 = vlen * ( s + 1 );
-
-				var a = layeroffset + j + slen1,
-					b = layeroffset + k + slen1,
-					c = layeroffset + k + slen2,
-					d = layeroffset + j + slen2;
-
-				f4( a, b, c, d, contour, s, sl, j, k );
-
-			}
-		}
-
-	}
-
-
-	function v( x, y, z ) {
-
-		scope.vertices.push( new THREE.Vector3( x, y, z ) );
-
-	}
-
-	function f3( a, b, c, isBottom ) {
-
-		a += shapesOffset;
-		b += shapesOffset;
-		c += shapesOffset;
-
-		// normal, color, material
-		scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) );
-
-		var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c );
-
- 		scope.faceVertexUvs[ 0 ].push( uvs );
-
-	}
-
-	function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {
-
-		a += shapesOffset;
-		b += shapesOffset;
-		c += shapesOffset;
-		d += shapesOffset;
-
- 		scope.faces.push( new THREE.Face4( a, b, c, d, null, null, extrudeMaterial ) );
-
- 		var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d,
- 		                                    stepIndex, stepsLength, contourIndex1, contourIndex2 );
- 		scope.faceVertexUvs[ 0 ].push( uvs );
-
-	}
-
-};
-
-THREE.ExtrudeGeometry.WorldUVGenerator = {
-
-	generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) {
-		var ax = geometry.vertices[ indexA ].x,
-			ay = geometry.vertices[ indexA ].y,
-
-			bx = geometry.vertices[ indexB ].x,
-			by = geometry.vertices[ indexB ].y,
-
-			cx = geometry.vertices[ indexC ].x,
-			cy = geometry.vertices[ indexC ].y;
-
-		return [
-			new THREE.Vector2( ax, ay ),
-			new THREE.Vector2( bx, by ),
-			new THREE.Vector2( cx, cy )
-		];
-
-	},
-
-	generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) {
-
-		return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC );
-
-	},
-
-	generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions,
-	                              indexA, indexB, indexC, indexD, stepIndex, stepsLength,
-	                              contourIndex1, contourIndex2 ) {
-
-		var ax = geometry.vertices[ indexA ].x,
-			ay = geometry.vertices[ indexA ].y,
-			az = geometry.vertices[ indexA ].z,
-
-			bx = geometry.vertices[ indexB ].x,
-			by = geometry.vertices[ indexB ].y,
-			bz = geometry.vertices[ indexB ].z,
-
-			cx = geometry.vertices[ indexC ].x,
-			cy = geometry.vertices[ indexC ].y,
-			cz = geometry.vertices[ indexC ].z,
-
-			dx = geometry.vertices[ indexD ].x,
-			dy = geometry.vertices[ indexD ].y,
-			dz = geometry.vertices[ indexD ].z;
-
-		if ( Math.abs( ay - by ) < 0.01 ) {
-			return [
-				new THREE.Vector2( ax, 1 - az ),
-				new THREE.Vector2( bx, 1 - bz ),
-				new THREE.Vector2( cx, 1 - cz ),
-				new THREE.Vector2( dx, 1 - dz )
-			];
-		} else {
-			return [
-				new THREE.Vector2( ay, 1 - az ),
-				new THREE.Vector2( by, 1 - bz ),
-				new THREE.Vector2( cy, 1 - cz ),
-				new THREE.Vector2( dy, 1 - dz )
-			];
-		}
-	}
-};
-
-THREE.ExtrudeGeometry.__v1 = new THREE.Vector2();
-THREE.ExtrudeGeometry.__v2 = new THREE.Vector2();
-THREE.ExtrudeGeometry.__v3 = new THREE.Vector2();
-THREE.ExtrudeGeometry.__v4 = new THREE.Vector2();
-THREE.ExtrudeGeometry.__v5 = new THREE.Vector2();
-THREE.ExtrudeGeometry.__v6 = new THREE.Vector2();
-/**
- * @author jonobr1 / http://jonobr1.com
- *
- * Creates a one-sided polygonal geometry from a path shape. Similar to
- * ExtrudeGeometry.
- *
- * parameters = {
- *
- *	curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT.
- *
- *	material: <int> // material index for front and back faces
- *	uvGenerator: <Object> // object that provides UV generator functions
- *
- * }
- **/
-
-THREE.ShapeGeometry = function ( shapes, options ) {
-
-	THREE.Geometry.call( this );
-
-	if ( shapes instanceof Array === false ) shapes = [ shapes ];
-
-	this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox();
-
-	this.addShapeList( shapes, options );
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-};
-
-THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype );
-
-/**
- * Add an array of shapes to THREE.ShapeGeometry.
- */
-THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) {
-
-	for ( var i = 0, l = shapes.length; i < l; i++ ) {
-
-		this.addShape( shapes[ i ], options );
-
-	}
-
-	return this;
-
-};
-
-/**
- * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry.
- */
-THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) {
-
-	if ( options === undefined ) options = {};
-	var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
-
-	var material = options.material;
-	var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator;
-
-	var shapebb = this.shapebb;
-
-	//
-
-	var i, l, hole, s;
-
-	var shapesOffset = this.vertices.length;
-	var shapePoints = shape.extractPoints( curveSegments );
-
-	var vertices = shapePoints.shape;
-	var holes = shapePoints.holes;
-
-	var reverse = !THREE.Shape.Utils.isClockWise( vertices );
-
-	if ( reverse ) {
-
-		vertices = vertices.reverse();
-
-		// Maybe we should also check if holes are in the opposite direction, just to be safe...
-
-		for ( i = 0, l = holes.length; i < l; i++ ) {
-
-			hole = holes[ i ];
-
-			if ( THREE.Shape.Utils.isClockWise( hole ) ) {
-
-				holes[ i ] = hole.reverse();
-
-			}
-
-		}
-
-		reverse = false;
-
-	}
-
-	var faces = THREE.Shape.Utils.triangulateShape( vertices, holes );
-
-	// Vertices
-
-	var contour = vertices;
-
-	for ( i = 0, l = holes.length; i < l; i++ ) {
-
-		hole = holes[ i ];
-		vertices = vertices.concat( hole );
-
-	}
-
-	//
-
-	var vert, vlen = vertices.length;
-	var face, flen = faces.length;
-	var cont, clen = contour.length;
-
-	for ( i = 0; i < vlen; i++ ) {
-
-		vert = vertices[ i ];
-
-		this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) );
-
-	}
-
-	for ( i = 0; i < flen; i++ ) {
-
-		face = faces[ i ];
-
-		var a = face[ 0 ] + shapesOffset;
-		var b = face[ 1 ] + shapesOffset;
-		var c = face[ 2 ] + shapesOffset;
-
-		this.faces.push( new THREE.Face3( a, b, c, null, null, material ) );
-		this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) );
-
-	}
-
-};
-/**
- * @author astrodud / http://astrodud.isgreat.org/
- * @author zz85 / https://github.com/zz85
- * @author bhouston / http://exocortex.com
- */
-
-// points - to create a closed torus, one must use a set of points 
-//    like so: [ a, b, c, d, a ], see first is the same as last.
-// segments - the number of circumference segments to create
-// phiStart - the starting radian
-// phiLength - the radian (0 to 2*PI) range of the lathed section
-//    2*pi is a closed lathe, less than 2PI is a portion.
-THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) {
-
-	THREE.Geometry.call( this );
-
-	segments = segments || 12;
-	phiStart = phiStart || 0;
-	phiLength = phiLength || 2 * Math.PI;
-
-	var inversePointLength = 1.0 / ( points.length - 1 );
-	var inverseSegments = 1.0 / segments;
-
-	for ( var i = 0, il = segments; i <= il; i ++ ) {
-
-		var phi = phiStart + i * inverseSegments * phiLength;
-
-		var c = Math.cos( phi ),
-			s = Math.sin( phi );
-
-		for ( var j = 0, jl = points.length; j < jl; j ++ ) {
-
-			var pt = points[ j ];
-
-			var vertex = new THREE.Vector3();
-
-			vertex.x = c * pt.x - s * pt.y;
-			vertex.y = s * pt.x + c * pt.y;
-			vertex.z = pt.z;
-
-			this.vertices.push( vertex );
-
-		}
-
-	}
-
-	var np = points.length;
-
-	for ( var i = 0, il = segments; i < il; i ++ ) {
-
-		for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) {
-
-			var base = j + np * i;
-			var a = base;
-			var b = base + np;
-			var c = base + 1 + np;
-			var d = base + 1;
-
-			this.faces.push( new THREE.Face4( a, b, c, d ) );
-
-			var u0 = i * inverseSegments;
-			var v0 = j * inversePointLength;
-			var u1 = u0 + inverseSegments;
-			var v1 = v0 + inversePointLength;
-
-			this.faceVertexUvs[ 0 ].push( [
-
-				new THREE.Vector2( u0, v0 ), 
-				new THREE.Vector2( u1, v0 ),
-				new THREE.Vector2( u1, v1 ),
-				new THREE.Vector2( u0, v1 )
-
-			] );
-
-		}
-
-	}
-
-	this.mergeVertices();
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
-};
-
-THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author mrdoob / http://mrdoob.com/
- * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
- */
-
-THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) {
-
-	THREE.Geometry.call( this );
-
-	this.width = width;
-	this.height = height;
-
-	this.widthSegments = widthSegments || 1;
-	this.heightSegments = heightSegments || 1;
-
-	var ix, iz;
-	var width_half = width / 2;
-	var height_half = height / 2;
-
-	var gridX = this.widthSegments;
-	var gridZ = this.heightSegments;
-
-	var gridX1 = gridX + 1;
-	var gridZ1 = gridZ + 1;
-
-	var segment_width = this.width / gridX;
-	var segment_height = this.height / gridZ;
-
-	var normal = new THREE.Vector3( 0, 0, 1 );
-
-	for ( iz = 0; iz < gridZ1; iz ++ ) {
-
-		for ( ix = 0; ix < gridX1; ix ++ ) {
-
-			var x = ix * segment_width - width_half;
-			var y = iz * segment_height - height_half;
-
-			this.vertices.push( new THREE.Vector3( x, - y, 0 ) );
-
-		}
-
-	}
-
-	for ( iz = 0; iz < gridZ; iz ++ ) {
-
-		for ( ix = 0; ix < gridX; ix ++ ) {
-
-			var a = ix + gridX1 * iz;
-			var b = ix + gridX1 * ( iz + 1 );
-			var c = ( ix + 1 ) + gridX1 * ( iz + 1 );
-			var d = ( ix + 1 ) + gridX1 * iz;
-
-			var face = new THREE.Face4( a, b, c, d );
-			face.normal.copy( normal );
-			face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );
-
-			this.faces.push( face );
-			this.faceVertexUvs[ 0 ].push( [
-				new THREE.Vector2( ix / gridX, 1 - iz / gridZ ),
-				new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ),
-				new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ),
-				new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ )
-			] );
-
-		}
-
-	}
-
-	this.computeCentroids();
-
-};
-
-THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author Kaleb Murphy
- */
-
-THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
-
-	THREE.Geometry.call( this );
-
-	innerRadius = innerRadius || 0;
-	outerRadius = outerRadius || 50;
-
-	thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
-
-	thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
-	phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8;
-
-	var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
-
-	for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring
-
-		for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle
-
-			var vertex = new THREE.Vector3();
-			var segment = thetaStart + o / thetaSegments * thetaLength;
-
-			vertex.x = radius * Math.cos( segment );
-			vertex.y = radius * Math.sin( segment );
-
-			this.vertices.push( vertex );
-			uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, - ( vertex.y / radius + 1 ) / 2 + 1 ) );
-		}
-
-		radius += radiusStep;
-
-	}
-
-	var n = new THREE.Vector3( 0, 0, 1 );
-
-	for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring
-
-		var thetaSegment = i * thetaSegments;
-
-		for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle
-
-			var segment = o + thetaSegment;
-
-			var v1 = segment + i;
-			var v2 = segment + thetaSegments + i;
-			var v3 = segment + thetaSegments + 1 + i;
-
-			this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) );
-			this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ], uvs[ v2 ], uvs[ v3 ] ]);
-
-			v1 = segment + i;
-			v2 = segment + thetaSegments + 1 + i;
-			v3 = segment + 1 + i;
-
-			this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) );
-			this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ], uvs[ v2 ], uvs[ v3 ] ]);
-
-		}
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
-
-};
-
-THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
-
-	THREE.Geometry.call( this );
-
-	this.radius = radius = radius || 50;
-
-	this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
-	this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
-
-	this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0;
-	this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
-
-	this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
-
-	var x, y, vertices = [], uvs = [];
-
-	for ( y = 0; y <= heightSegments; y ++ ) {
-
-		var verticesRow = [];
-		var uvsRow = [];
-
-		for ( x = 0; x <= widthSegments; x ++ ) {
-
-			var u = x / widthSegments;
-			var v = y / heightSegments;
-
-			var vertex = new THREE.Vector3();
-			vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
-			vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
-			vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
-
-			this.vertices.push( vertex );
-
-			verticesRow.push( this.vertices.length - 1 );
-			uvsRow.push( new THREE.Vector2( u, 1 - v ) );
-
-		}
-
-		vertices.push( verticesRow );
-		uvs.push( uvsRow );
-
-	}
-
-	for ( y = 0; y < this.heightSegments; y ++ ) {
-
-		for ( x = 0; x < this.widthSegments; x ++ ) {
-
-			var v1 = vertices[ y ][ x + 1 ];
-			var v2 = vertices[ y ][ x ];
-			var v3 = vertices[ y + 1 ][ x ];
-			var v4 = vertices[ y + 1 ][ x + 1 ];
-
-			var n1 = this.vertices[ v1 ].clone().normalize();
-			var n2 = this.vertices[ v2 ].clone().normalize();
-			var n3 = this.vertices[ v3 ].clone().normalize();
-			var n4 = this.vertices[ v4 ].clone().normalize();
-
-			var uv1 = uvs[ y ][ x + 1 ].clone();
-			var uv2 = uvs[ y ][ x ].clone();
-			var uv3 = uvs[ y + 1 ][ x ].clone();
-			var uv4 = uvs[ y + 1 ][ x + 1 ].clone();
-
-			if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) {
-
-				this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) );
-				this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] );
-
-			} else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) {
-
-				this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
-				this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
-
-			} else {
-
-				this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
-				this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );
-
-			}
-
-		}
-
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-
-	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
-
-};
-
-THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author alteredq / http://alteredqualia.com/
- *
- * For creating 3D text geometry in three.js
- *
- * Text = 3D Text
- *
- * parameters = {
- *  size: 			<float>, 	// size of the text
- *  height: 		<float>, 	// thickness to extrude text
- *  curveSegments: 	<int>,		// number of points on the curves
- *
- *  font: 			<string>,		// font name
- *  weight: 		<string>,		// font weight (normal, bold)
- *  style: 			<string>,		// font style  (normal, italics)
- *
- *  bevelEnabled:	<bool>,			// turn on bevel
- *  bevelThickness: <float>, 		// how deep into text bevel goes
- *  bevelSize:		<float>, 		// how far from text outline is bevel
- *  }
- *
- */
-
-/*	Usage Examples
-
-	// TextGeometry wrapper
-
-	var text3d = new TextGeometry( text, options );
-
-	// Complete manner
-
-	var textShapes = THREE.FontUtils.generateShapes( text, options );
-	var text3d = new ExtrudeGeometry( textShapes, options );
-
-*/
-
-
-THREE.TextGeometry = function ( text, parameters ) {
-
-	parameters = parameters || {};
-
-	var textShapes = THREE.FontUtils.generateShapes( text, parameters );
-
-	// translate parameters to ExtrudeGeometry API
-
-	parameters.amount = parameters.height !== undefined ? parameters.height : 50;
-
-	// defaults
-
-	if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
-	if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
-	if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
-
-	THREE.ExtrudeGeometry.call( this, textShapes, parameters );
-
-};
-
-THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype );
-/**
- * @author oosmoxiecode
- * @author mrdoob / http://mrdoob.com/
- * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888
- */
-
-THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) {
-
-	THREE.Geometry.call( this );
-
-	var scope = this;
-
-	this.radius = radius || 100;
-	this.tube = tube || 40;
-	this.radialSegments = radialSegments || 8;
-	this.tubularSegments = tubularSegments || 6;
-	this.arc = arc || Math.PI * 2;
-
-	var center = new THREE.Vector3(), uvs = [], normals = [];
-
-	for ( var j = 0; j <= this.radialSegments; j ++ ) {
-
-		for ( var i = 0; i <= this.tubularSegments; i ++ ) {
-
-			var u = i / this.tubularSegments * this.arc;
-			var v = j / this.radialSegments * Math.PI * 2;
-
-			center.x = this.radius * Math.cos( u );
-			center.y = this.radius * Math.sin( u );
-
-			var vertex = new THREE.Vector3();
-			vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u );
-			vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u );
-			vertex.z = this.tube * Math.sin( v );
-
-			this.vertices.push( vertex );
-
-			uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) );
-			normals.push( vertex.clone().sub( center ).normalize() );
-
-		}
-	}
-
-
-	for ( var j = 1; j <= this.radialSegments; j ++ ) {
-
-		for ( var i = 1; i <= this.tubularSegments; i ++ ) {
-
-			var a = ( this.tubularSegments + 1 ) * j + i - 1;
-			var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1;
-			var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i;
-			var d = ( this.tubularSegments + 1 ) * j + i;
-
-			var face = new THREE.Face4( a, b, c, d, [ normals[ a ], normals[ b ], normals[ c ], normals[ d ] ] );
-			face.normal.add( normals[ a ] );
-			face.normal.add( normals[ b ] );
-			face.normal.add( normals[ c ] );
-			face.normal.add( normals[ d ] );
-			face.normal.normalize();
-
-			this.faces.push( face );
-
-			this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] );
-		}
-
-	}
-
-	this.computeCentroids();
-
-};
-
-THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author oosmoxiecode
- * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
- */
-
-THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) {
-
-	THREE.Geometry.call( this );
-
-	var scope = this;
-
-	this.radius = radius || 100;
-	this.tube = tube || 40;
-	this.radialSegments = radialSegments || 64;
-	this.tubularSegments = tubularSegments || 8;
-	this.p = p || 2;
-	this.q = q || 3;
-	this.heightScale = heightScale || 1;
-	this.grid = new Array( this.radialSegments );
-
-	var tang = new THREE.Vector3();
-	var n = new THREE.Vector3();
-	var bitan = new THREE.Vector3();
-
-	for ( var i = 0; i < this.radialSegments; ++ i ) {
-
-		this.grid[ i ] = new Array( this.tubularSegments );
-
-		for ( var j = 0; j < this.tubularSegments; ++ j ) {
-
-			var u = i / this.radialSegments * 2 * this.p * Math.PI;
-			var v = j / this.tubularSegments * 2 * Math.PI;
-			var p1 = getPos( u, v, this.q, this.p, this.radius, this.heightScale );
-			var p2 = getPos( u + 0.01, v, this.q, this.p, this.radius, this.heightScale );
-			var cx, cy;
-
-			tang.subVectors( p2, p1 );
-			n.addVectors( p2, p1 );
-
-			bitan.crossVectors( tang, n );
-			n.crossVectors( bitan, tang );
-			bitan.normalize();
-			n.normalize();
-
-			cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
-			cy = this.tube * Math.sin( v );
-
-			p1.x += cx * n.x + cy * bitan.x;
-			p1.y += cx * n.y + cy * bitan.y;
-			p1.z += cx * n.z + cy * bitan.z;
-
-			this.grid[ i ][ j ] = vert( p1.x, p1.y, p1.z );
-
-		}
-
-	}
-
-	for ( var i = 0; i < this.radialSegments; ++ i ) {
-
-		for ( var j = 0; j < this.tubularSegments; ++ j ) {
-
-			var ip = ( i + 1 ) % this.radialSegments;
-			var jp = ( j + 1 ) % this.tubularSegments;
-
-			var a = this.grid[ i ][ j ];
-			var b = this.grid[ ip ][ j ];
-			var c = this.grid[ ip ][ jp ];
-			var d = this.grid[ i ][ jp ];
-
-			var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments );
-			var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments );
-			var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments );
-			var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments );
-
-			this.faces.push( new THREE.Face4( a, b, c, d ) );
-			this.faceVertexUvs[ 0 ].push( [ uva,uvb,uvc, uvd ] );
-
-		}
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
-	function vert( x, y, z ) {
-
-		return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;
-
-	}
-
-	function getPos( u, v, in_q, in_p, radius, heightScale ) {
-
-		var cu = Math.cos( u );
-		var cv = Math.cos( v );
-		var su = Math.sin( u );
-		var quOverP = in_q / in_p * u;
-		var cs = Math.cos( quOverP );
-
-		var tx = radius * ( 2 + cs ) * 0.5 * cu;
-		var ty = radius * ( 2 + cs ) * su * 0.5;
-		var tz = heightScale * radius * Math.sin( quOverP ) * 0.5;
-
-		return new THREE.Vector3( tx, ty, tz );
-
-	}
-
-};
-
-THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author WestLangley / https://github.com/WestLangley
- * @author zz85 / https://github.com/zz85
- * @author miningold / https://github.com/miningold
- *
- * Modified from the TorusKnotGeometry by @oosmoxiecode
- *
- * Creates a tube which extrudes along a 3d spline
- *
- * Uses parallel transport frames as described in
- * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
- */
-
-THREE.TubeGeometry = function( path, segments, radius, radiusSegments, closed, debug ) {
-
-	THREE.Geometry.call( this );
-
-	this.path = path;
-	this.segments = segments || 64;
-	this.radius = radius || 1;
-	this.radiusSegments = radiusSegments || 8;
-	this.closed = closed || false;
-
-	if ( debug ) this.debug = new THREE.Object3D();
-
-	this.grid = [];
-
-	var scope = this,
-
-		tangent,
-		normal,
-		binormal,
-
-		numpoints = this.segments + 1,
-
-		x, y, z,
-		tx, ty, tz,
-		u, v,
-
-		cx, cy,
-		pos, pos2 = new THREE.Vector3(),
-		i, j,
-		ip, jp,
-		a, b, c, d,
-		uva, uvb, uvc, uvd;
-
-	var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ),
-		tangents = frames.tangents,
-		normals = frames.normals,
-		binormals = frames.binormals;
-
-	// proxy internals
-	this.tangents = tangents;
-	this.normals = normals;
-	this.binormals = binormals;
-
-	function vert( x, y, z ) {
-
-		return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;
-
-	}
-
-
-	// consruct the grid
-
-	for ( i = 0; i < numpoints; i++ ) {
-
-		this.grid[ i ] = [];
-
-		u = i / ( numpoints - 1 );
-
-		pos = path.getPointAt( u );
-
-		tangent = tangents[ i ];
-		normal = normals[ i ];
-		binormal = binormals[ i ];
-
-		if ( this.debug ) {
-
-			this.debug.add( new THREE.ArrowHelper(tangent, pos, radius, 0x0000ff ) );
-			this.debug.add( new THREE.ArrowHelper(normal, pos, radius, 0xff0000 ) );
-			this.debug.add( new THREE.ArrowHelper(binormal, pos, radius, 0x00ff00 ) );
-
-		}
-
-		for ( j = 0; j < this.radiusSegments; j++ ) {
-
-			v = j / this.radiusSegments * 2 * Math.PI;
-
-			cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
-			cy = this.radius * Math.sin( v );
-
-			pos2.copy( pos );
-			pos2.x += cx * normal.x + cy * binormal.x;
-			pos2.y += cx * normal.y + cy * binormal.y;
-			pos2.z += cx * normal.z + cy * binormal.z;
-
-			this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
-
-		}
-	}
-
-
-	// construct the mesh
-
-	for ( i = 0; i < this.segments; i++ ) {
-
-		for ( j = 0; j < this.radiusSegments; j++ ) {
-
-			ip = ( this.closed ) ? (i + 1) % this.segments : i + 1;
-			jp = (j + 1) % this.radiusSegments;
-
-			a = this.grid[ i ][ j ];		// *** NOT NECESSARILY PLANAR ! ***
-			b = this.grid[ ip ][ j ];
-			c = this.grid[ ip ][ jp ];
-			d = this.grid[ i ][ jp ];
-
-			uva = new THREE.Vector2( i / this.segments, j / this.radiusSegments );
-			uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radiusSegments );
-			uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radiusSegments );
-			uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radiusSegments );
-
-			this.faces.push( new THREE.Face4( a, b, c, d ) );
-			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvc, uvd ] );
-
-		}
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
-};
-
-THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
-
-
-// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
-THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) {
-
-	var	tangent = new THREE.Vector3(),
-		normal = new THREE.Vector3(),
-		binormal = new THREE.Vector3(),
-
-		tangents = [],
-		normals = [],
-		binormals = [],
-
-		vec = new THREE.Vector3(),
-		mat = new THREE.Matrix4(),
-
-		numpoints = segments + 1,
-		theta,
-		epsilon = 0.0001,
-		smallest,
-
-		tx, ty, tz,
-		i, u, v;
-
-
-	// expose internals
-	this.tangents = tangents;
-	this.normals = normals;
-	this.binormals = binormals;
-
-	// compute the tangent vectors for each segment on the path
-
-	for ( i = 0; i < numpoints; i++ ) {
-
-		u = i / ( numpoints - 1 );
-
-		tangents[ i ] = path.getTangentAt( u );
-		tangents[ i ].normalize();
-
-	}
-
-	initialNormal3();
-
-	function initialNormal1(lastBinormal) {
-		// fixed start binormal. Has dangers of 0 vectors
-		normals[ 0 ] = new THREE.Vector3();
-		binormals[ 0 ] = new THREE.Vector3();
-		if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
-		normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize();
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
-	}
-
-	function initialNormal2() {
-
-		// This uses the Frenet-Serret formula for deriving binormal
-		var t2 = path.getTangentAt( epsilon );
-
-		normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize();
-		binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] );
-
-		normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
-
-	}
-
-	function initialNormal3() {
-		// select an initial normal vector perpenicular to the first tangent vector,
-		// and in the direction of the smallest tangent xyz component
-
-		normals[ 0 ] = new THREE.Vector3();
-		binormals[ 0 ] = new THREE.Vector3();
-		smallest = Number.MAX_VALUE;
-		tx = Math.abs( tangents[ 0 ].x );
-		ty = Math.abs( tangents[ 0 ].y );
-		tz = Math.abs( tangents[ 0 ].z );
-
-		if ( tx <= smallest ) {
-			smallest = tx;
-			normal.set( 1, 0, 0 );
-		}
-
-		if ( ty <= smallest ) {
-			smallest = ty;
-			normal.set( 0, 1, 0 );
-		}
-
-		if ( tz <= smallest ) {
-			normal.set( 0, 0, 1 );
-		}
-
-		vec.crossVectors( tangents[ 0 ], normal ).normalize();
-
-		normals[ 0 ].crossVectors( tangents[ 0 ], vec );
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
-	}
-
-
-	// compute the slowly-varying normal and binormal vectors for each segment on the path
-
-	for ( i = 1; i < numpoints; i++ ) {
-
-		normals[ i ] = normals[ i-1 ].clone();
-
-		binormals[ i ] = binormals[ i-1 ].clone();
-
-		vec.crossVectors( tangents[ i-1 ], tangents[ i ] );
-
-		if ( vec.length() > epsilon ) {
-
-			vec.normalize();
-
-			theta = Math.acos( tangents[ i-1 ].dot( tangents[ i ] ) );
-
-			normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
-
-		}
-
-		binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
-
-	}
-
-
-	// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
-
-	if ( closed ) {
-
-		theta = Math.acos( normals[ 0 ].dot( normals[ numpoints-1 ] ) );
-		theta /= ( numpoints - 1 );
-
-		if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) {
-
-			theta = -theta;
-
-		}
-
-		for ( i = 1; i < numpoints; i++ ) {
-
-			// twist a little...
-			normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
-			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
-
-		}
-
-	}
-};
-/**
- * @author clockworkgeek / https://github.com/clockworkgeek
- * @author timothypratley / https://github.com/timothypratley
- * @author WestLangley / http://github.com/WestLangley
-*/
-
-THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) {
-
-	THREE.Geometry.call( this );
-
-	radius = radius || 1;
-	detail = detail || 0;
-
-	var that = this;
-
-	for ( var i = 0, l = vertices.length; i < l; i ++ ) {
-
-		prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) );
-
-	}
-
-	var midpoints = [], p = this.vertices;
-
-	var f = [];
-	for ( var i = 0, l = faces.length; i < l; i ++ ) {
-
-		var v1 = p[ faces[ i ][ 0 ] ];
-		var v2 = p[ faces[ i ][ 1 ] ];
-		var v3 = p[ faces[ i ][ 2 ] ];
-
-		f[ i ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );
-
-	}
-
-	for ( var i = 0, l = f.length; i < l; i ++ ) {
-
-		subdivide(f[ i ], detail);
-
-	}
-
-
-	// Handle case when face straddles the seam
-
-	for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) {
-
-		var uvs = this.faceVertexUvs[ 0 ][ i ];
-
-		var x0 = uvs[ 0 ].x;
-		var x1 = uvs[ 1 ].x;
-		var x2 = uvs[ 2 ].x;
-
-		var max = Math.max( x0, Math.max( x1, x2 ) );
-		var min = Math.min( x0, Math.min( x1, x2 ) );
-
-		if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary
-
-			if ( x0 < 0.2 ) uvs[ 0 ].x += 1;
-			if ( x1 < 0.2 ) uvs[ 1 ].x += 1;
-			if ( x2 < 0.2 ) uvs[ 2 ].x += 1;
-
-		}
-
-	}
-
-
-	// Merge vertices
-
-	this.mergeVertices();
-
-
-	// Apply radius
-
-	for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {
-
-		this.vertices[ i ].multiplyScalar( radius );
-
-	}
-
-
-	// Project vector onto sphere's surface
-
-	function prepare( vector ) {
-
-		var vertex = vector.normalize().clone();
-		vertex.index = that.vertices.push( vertex ) - 1;
-
-		// Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle.
-
-		var u = azimuth( vector ) / 2 / Math.PI + 0.5;
-		var v = inclination( vector ) / Math.PI + 0.5;
-		vertex.uv = new THREE.Vector2( u, 1 - v );
-
-		return vertex;
-
-	}
-
-
-	// Approximate a curved face with recursively sub-divided triangles.
-
-	function make( v1, v2, v3 ) {
-
-		var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );
-		face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 );
-		face.normal.copy( face.centroid ).normalize();
-		that.faces.push( face );
-
-		var azi = azimuth( face.centroid );
-
-		that.faceVertexUvs[ 0 ].push( [
-			correctUV( v1.uv, v1, azi ),
-			correctUV( v2.uv, v2, azi ),
-			correctUV( v3.uv, v3, azi )
-		] );
-
-	}
-
-
-	// Analytically subdivide a face to the required detail level.
-
-	function subdivide(face, detail ) {
-
-		var cols = Math.pow(2, detail);
-		var cells = Math.pow(4, detail);
-		var a = prepare( that.vertices[ face.a ] );
-		var b = prepare( that.vertices[ face.b ] );
-		var c = prepare( that.vertices[ face.c ] );
-		var v = [];
-
-		// Construct all of the vertices for this subdivision.
-
-		for ( var i = 0 ; i <= cols; i ++ ) {
-
-			v[ i ] = [];
-
-			var aj = prepare( a.clone().lerp( c, i / cols ) );
-			var bj = prepare( b.clone().lerp( c, i / cols ) );
-			var rows = cols - i;
-
-			for ( var j = 0; j <= rows; j ++) {
-
-				if ( j == 0 && i == cols ) {
-
-					v[ i ][ j ] = aj;
-
-				} else {
-
-					v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) );
-
-				}
-
-			}
-
-		}
-
-		// Construct all of the faces.
-
-		for ( var i = 0; i < cols ; i ++ ) {
-
-			for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) {
-
-				var k = Math.floor( j / 2 );
-
-				if ( j % 2 == 0 ) {
-
-					make(
-						v[ i ][ k + 1],
-						v[ i + 1 ][ k ],
-						v[ i ][ k ]
-					);
-
-				} else {
-
-					make(
-						v[ i ][ k + 1 ],
-						v[ i + 1][ k + 1],
-						v[ i + 1 ][ k ]
-					);
-
-				}
-
-			}
-
-		}
-
-	}
-
-
-	// Angle around the Y axis, counter-clockwise when looking from above.
-
-	function azimuth( vector ) {
-
-		return Math.atan2( vector.z, -vector.x );
-
-	}
-
-
-	// Angle above the XZ plane.
-
-	function inclination( vector ) {
-
-		return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
-
-	}
-
-
-	// Texture fixing helper. Spheres have some odd behaviours.
-
-	function correctUV( uv, vector, azimuth ) {
-
-		if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y );
-		if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y );
-		return uv.clone();
-
-	}
-
-	this.computeCentroids();
-
-	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
-
-};
-
-THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author timothypratley / https://github.com/timothypratley
- */
-
-THREE.IcosahedronGeometry = function ( radius, detail ) {
-
-	this.radius = radius;
-	this.detail = detail;
-
-	var t = ( 1 + Math.sqrt( 5 ) ) / 2;
-
-	var vertices = [
-		[ -1,  t,  0 ], [  1, t, 0 ], [ -1, -t,  0 ], [  1, -t,  0 ],
-		[  0, -1,  t ], [  0, 1, t ], [  0, -1, -t ], [  0,  1, -t ],
-		[  t,  0, -1 ], [  t, 0, 1 ], [ -t,  0, -1 ], [ -t,  0,  1 ]
-	];
-
-	var faces = [
-		[ 0, 11,  5 ], [ 0,  5,  1 ], [  0,  1,  7 ], [  0,  7, 10 ], [  0, 10, 11 ],
-		[ 1,  5,  9 ], [ 5, 11,  4 ], [ 11, 10,  2 ], [ 10,  7,  6 ], [  7,  1,  8 ],
-		[ 3,  9,  4 ], [ 3,  4,  2 ], [  3,  2,  6 ], [  3,  6,  8 ], [  3,  8,  9 ],
-		[ 4,  9,  5 ], [ 2,  4, 11 ], [  6,  2, 10 ], [  8,  6,  7 ], [  9,  8,  1 ]
-	];
-
-	THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );
-
-};
-
-THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author timothypratley / https://github.com/timothypratley
- */
-
-THREE.OctahedronGeometry = function ( radius, detail ) {
-
-	var vertices = [
-		[ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ]
-	];
-
-	var faces = [
-		[ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ]
-	];
-
-	THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );
-};
-
-THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author timothypratley / https://github.com/timothypratley
- */
-
-THREE.TetrahedronGeometry = function ( radius, detail ) {
-
-	var vertices = [
-		[ 1,  1,  1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ]
-	];
-
-	var faces = [
-		[ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ]
-	];
-
-	THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );
-
-};
-
-THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author zz85 / https://github.com/zz85
- * Parametric Surfaces Geometry
- * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
- *
- * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements, useTris );
- *
- */
-
-THREE.ParametricGeometry = function ( func, slices, stacks, useTris ) {
-
-	THREE.Geometry.call( this );
-
-	var verts = this.vertices;
-	var faces = this.faces;
-	var uvs = this.faceVertexUvs[ 0 ];
-
-	useTris = (useTris === undefined) ? false : useTris;
-
-	var i, il, j, p;
-	var u, v;
-
-	var stackCount = stacks + 1;
-	var sliceCount = slices + 1;
-
-	for ( i = 0; i <= stacks; i ++ ) {
-
-		v = i / stacks;
-
-		for ( j = 0; j <= slices; j ++ ) {
-
-			u = j / slices;
-
-			p = func( u, v );
-			verts.push( p );
-
-		}
-	}
-
-	var a, b, c, d;
-	var uva, uvb, uvc, uvd;
-
-	for ( i = 0; i < stacks; i ++ ) {
-
-		for ( j = 0; j < slices; j ++ ) {
-
-			a = i * sliceCount + j;
-			b = i * sliceCount + j + 1;
-			c = (i + 1) * sliceCount + j;
-			d = (i + 1) * sliceCount + j + 1;
-
-			uva = new THREE.Vector2( j / slices, i / stacks );
-			uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks );
-			uvc = new THREE.Vector2( j / slices, ( i + 1 ) / stacks );
-			uvd = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks );
-
-			if ( useTris ) {
-
-				faces.push( new THREE.Face3( a, b, c ) );
-				faces.push( new THREE.Face3( b, d, c ) );
-
-				uvs.push( [ uva, uvb, uvc ] );
-				uvs.push( [ uvb, uvd, uvc ] );
-
-			} else {
-
-				faces.push( new THREE.Face4( a, b, d, c ) );
-				uvs.push( [ uva, uvb, uvd, uvc ] );
-
-			}
-
-		}
-
-	}
-
-	// console.log(this);
-
-	// magic bullet
-	// var diff = this.mergeVertices();
-	// console.log('removed ', diff, ' vertices by merging');
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
-};
-
-THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author qiao / https://github.com/qiao
- * @fileoverview This is a convex hull generator using the incremental method. 
- * The complexity is O(n^2) where n is the number of vertices.
- * O(nlogn) algorithms do exist, but they are much more complicated.
- *
- * Benchmark: 
- *
- *  Platform: CPU: P7350 @2.00GHz Engine: V8
- *
- *  Num Vertices	Time(ms)
- *
- *     10           1
- *     20           3
- *     30           19
- *     40           48
- *     50           107
- */
-
-THREE.ConvexGeometry = function( vertices ) {
-
-	THREE.Geometry.call( this );
-
-	var faces = [ [ 0, 1, 2 ], [ 0, 2, 1 ] ]; 
-
-	for ( var i = 3; i < vertices.length; i++ ) {
-
-		addPoint( i );
-
-	}
-
-
-	function addPoint( vertexId ) {
-
-		var vertex = vertices[ vertexId ].clone();
-
-		var mag = vertex.length();
-		vertex.x += mag * randomOffset();
-		vertex.y += mag * randomOffset();
-		vertex.z += mag * randomOffset();
-
-		var hole = [];
-
-		for ( var f = 0; f < faces.length; ) {
-
-			var face = faces[ f ];
-
-			// for each face, if the vertex can see it,
-			// then we try to add the face's edges into the hole.
-			if ( visible( face, vertex ) ) {
-
-				for ( var e = 0; e < 3; e++ ) {
-
-					var edge = [ face[ e ], face[ ( e + 1 ) % 3 ] ];
-					var boundary = true;
-
-					// remove duplicated edges.
-					for ( var h = 0; h < hole.length; h++ ) {
-
-						if ( equalEdge( hole[ h ], edge ) ) {
-
-							hole[ h ] = hole[ hole.length - 1 ];
-							hole.pop();
-							boundary = false;
-							break;
-
-						}
-
-					}
-
-					if ( boundary ) {
-
-						hole.push( edge );
-
-					}
-
-				}
-
-				// remove faces[ f ]
-				faces[ f ] = faces[ faces.length - 1 ];
-				faces.pop();
-
-			} else { // not visible
-
-				f++;
-
-			}
-		}
-
-		// construct the new faces formed by the edges of the hole and the vertex
-		for ( var h = 0; h < hole.length; h++ ) {
-
-			faces.push( [ 
-				hole[ h ][ 0 ],
-				hole[ h ][ 1 ],
-				vertexId
-			] );
-
-		}
-	}
-
-	/**
-	 * Whether the face is visible from the vertex
-	 */
-	function visible( face, vertex ) {
-
-		var va = vertices[ face[ 0 ] ];
-		var vb = vertices[ face[ 1 ] ];
-		var vc = vertices[ face[ 2 ] ];
-
-		var n = normal( va, vb, vc );
-
-		// distance from face to origin
-		var dist = n.dot( va );
-
-		return n.dot( vertex ) >= dist; 
-
-	}
-
-	/**
-	 * Face normal
-	 */
-	function normal( va, vb, vc ) {
-
-		var cb = new THREE.Vector3();
-		var ab = new THREE.Vector3();
-
-		cb.subVectors( vc, vb );
-		ab.subVectors( va, vb );
-		cb.cross( ab );
-
-		cb.normalize();
-
-		return cb;
-
-	}
-
-	/**
-	 * Detect whether two edges are equal.
-	 * Note that when constructing the convex hull, two same edges can only
-	 * be of the negative direction.
-	 */
-	function equalEdge( ea, eb ) {
-
-		return ea[ 0 ] === eb[ 1 ] && ea[ 1 ] === eb[ 0 ]; 
-
-	}
-
-	/**
-	 * Create a random offset between -1e-6 and 1e-6.
-	 */
-	function randomOffset() {
-
-		return ( Math.random() - 0.5 ) * 2 * 1e-6;
-
-	}
-
-
-	/**
-	 * XXX: Not sure if this is the correct approach. Need someone to review.
-	 */
-	function vertexUv( vertex ) {
-
-		var mag = vertex.length();
-		return new THREE.Vector2( vertex.x / mag, vertex.y / mag );
-
-	}
-
-	// Push vertices into `this.vertices`, skipping those inside the hull
-	var id = 0;
-	var newId = new Array( vertices.length ); // map from old vertex id to new id
-
-	for ( var i = 0; i < faces.length; i++ ) {
-
-		 var face = faces[ i ];
-
-		 for ( var j = 0; j < 3; j++ ) {
-
-				if ( newId[ face[ j ] ] === undefined ) {
-
-						newId[ face[ j ] ] = id++;
-						this.vertices.push( vertices[ face[ j ] ] );
-
-				}
-
-				face[ j ] = newId[ face[ j ] ];
-
-		 }
-
-	}
-
-	// Convert faces into instances of THREE.Face3
-	for ( var i = 0; i < faces.length; i++ ) {
-
-		this.faces.push( new THREE.Face3( 
-				faces[ i ][ 0 ],
-				faces[ i ][ 1 ],
-				faces[ i ][ 2 ]
-		) );
-
-	}
-
-	// Compute UVs
-	for ( var i = 0; i < this.faces.length; i++ ) {
-
-		var face = this.faces[ i ];
-
-		this.faceVertexUvs[ 0 ].push( [
-			vertexUv( this.vertices[ face.a ] ),
-			vertexUv( this.vertices[ face.b ] ),
-			vertexUv( this.vertices[ face.c ])
-		] );
-
-	}
-
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
-};
-
-THREE.ConvexGeometry.prototype = Object.create( THREE.Geometry.prototype );
-/**
- * @author sroucheray / http://sroucheray.org/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.AxisHelper = function ( size ) {
-
-	size = size || 1;
-
-	var geometry = new THREE.Geometry();
-
-	geometry.vertices.push(
-		new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ),
-		new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ),
-		new THREE.Vector3(), new THREE.Vector3( 0, 0, size )
-	);
-
-	geometry.colors.push(
-		new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ),
-		new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ),
-		new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff )
-	);
-
-	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
-
-	THREE.Line.call( this, geometry, material, THREE.LinePieces );
-
-};
-
-THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype );
-/**
- * @author WestLangley / http://github.com/WestLangley
- * @author zz85 / http://github.com/zz85
- * @author bhouston / http://exocortex.com
- *
- * Creates an arrow for visualizing directions
- *
- * Parameters:
- *  dir - Vector3
- *  origin - Vector3
- *  length - Number
- *  hex - color in hex value
- */
-
-THREE.ArrowHelper = function ( dir, origin, length, hex ) {
-
-	// dir is assumed to be normalized
-
-	THREE.Object3D.call( this );
-
-	if ( hex === undefined ) hex = 0xffff00;
-	if ( length === undefined ) length = 1;
-
-	this.position = origin;
-
-	this.useQuaternion = true;
-
-	var lineGeometry = new THREE.Geometry();
-	lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) );
-	lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) );
-
-	this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) );
-	this.line.matrixAutoUpdate = false;
-	this.add( this.line );
-
-	var coneGeometry = new THREE.CylinderGeometry( 0, 0.05, 0.25, 5, 1 );
-	coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0.875, 0 ) );
-
-	this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) );
-	this.cone.matrixAutoUpdate = false;
-	this.add( this.cone );
-
-	this.setDirection( dir );
-	this.setLength( length );
-
-};
-
-THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.ArrowHelper.prototype.setDirection = function () {
-
-	var axis = new THREE.Vector3();
-	var radians;
-
-	return function ( dir ) {
-
-		// dir is assumed to be normalized
-
-		if ( dir.y > 0.999 ) {
-
-			this.quaternion.set( 0, 0, 0, 1 );
-
-		} else if ( dir.y < - 0.999 ) {
-
-			this.quaternion.set( 1, 0, 0, 0 );
-
-		} else {
-
-			axis.set( dir.z, 0, - dir.x ).normalize();
-
-			radians = Math.acos( dir.y );
-
-			this.quaternion.setFromAxisAngle( axis, radians );
-
-		}
-
-	};
-
-}();
-
-THREE.ArrowHelper.prototype.setLength = function ( length ) {
-
-	this.scale.set( length, length, length );
-
-};
-
-THREE.ArrowHelper.prototype.setColor = function ( hex ) {
-
-	this.line.material.color.setHex( hex );
-	this.cone.material.color.setHex( hex );
-
-};
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.BoxHelper = function ( size ) {
-
-	size = size || 1;
-
-	var geometry = new THREE.Geometry();
-
-	//   5____4
-	// 1/___0/|
-	// | 6__|_7
-	// 2/___3/
-
-	var vertices = [
-		new THREE.Vector3(   size,   size,   size ),
-		new THREE.Vector3( - size,   size,   size ),
-		new THREE.Vector3( - size, - size,   size ),
-		new THREE.Vector3(   size, - size,   size ),
-
-		new THREE.Vector3(   size,   size, - size ),
-		new THREE.Vector3( - size,   size, - size ),
-		new THREE.Vector3( - size, - size, - size ),
-		new THREE.Vector3(   size, - size, - size )
-	];
-
-	// TODO: Wouldn't be nice if Line had .segments?
-
-	geometry.vertices.push(
-		vertices[ 0 ], vertices[ 1 ],
-		vertices[ 1 ], vertices[ 2 ],
-		vertices[ 2 ], vertices[ 3 ],
-		vertices[ 3 ], vertices[ 0 ],
-
-		vertices[ 4 ], vertices[ 5 ],
-		vertices[ 5 ], vertices[ 6 ],
-		vertices[ 6 ], vertices[ 7 ],
-		vertices[ 7 ], vertices[ 4 ],
-
-		vertices[ 0 ], vertices[ 4 ],
-		vertices[ 1 ], vertices[ 5 ],
-		vertices[ 2 ], vertices[ 6 ],
-		vertices[ 3 ], vertices[ 7 ]
-	);
-
-	this.vertices = vertices;
-
-	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial(), THREE.LinePieces );
-
-};
-
-THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype );
-
-THREE.BoxHelper.prototype.update = function ( object ) {
-
-	var geometry = object.geometry;
-
-	if ( geometry.boundingBox === null ) {
-
-		geometry.computeBoundingBox();
-
-	}
-
-	var min = geometry.boundingBox.min;
-	var max = geometry.boundingBox.max;
-	var vertices = this.vertices;
-
-	vertices[ 0 ].set( max.x, max.y, max.z );
-	vertices[ 1 ].set( min.x, max.y, max.z );
-	vertices[ 2 ].set( min.x, min.y, max.z );
-	vertices[ 3 ].set( max.x, min.y, max.z );
-	vertices[ 4 ].set( max.x, max.y, min.z );
-	vertices[ 5 ].set( min.x, max.y, min.z );
-	vertices[ 6 ].set( min.x, min.y, min.z );
-	vertices[ 7 ].set( max.x, min.y, min.z );
-
-	this.geometry.computeBoundingSphere();
-	this.geometry.verticesNeedUpdate = true;
-
-	this.matrixAutoUpdate = false;
-	this.matrixWorld = object.matrixWorld;
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- *	- shows frustum, line of sight and up of the camera
- *	- suitable for fast updates
- * 	- based on frustum visualization in lightgl.js shadowmap example
- *		http://evanw.github.com/lightgl.js/tests/shadowmap.html
- */
-
-THREE.CameraHelper = function ( camera ) {
-
-	THREE.Line.call( this );
-
-	var geometry = new THREE.Geometry();
-	var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } );
-
-	var pointMap = {};
-
-	// colors
-
-	var hexFrustum = 0xffaa00;
-	var hexCone = 0xff0000;
-	var hexUp = 0x00aaff;
-	var hexTarget = 0xffffff;
-	var hexCross = 0x333333;
-
-	// near
-
-	addLine( "n1", "n2", hexFrustum );
-	addLine( "n2", "n4", hexFrustum );
-	addLine( "n4", "n3", hexFrustum );
-	addLine( "n3", "n1", hexFrustum );
-
-	// far
-
-	addLine( "f1", "f2", hexFrustum );
-	addLine( "f2", "f4", hexFrustum );
-	addLine( "f4", "f3", hexFrustum );
-	addLine( "f3", "f1", hexFrustum );
-
-	// sides
-
-	addLine( "n1", "f1", hexFrustum );
-	addLine( "n2", "f2", hexFrustum );
-	addLine( "n3", "f3", hexFrustum );
-	addLine( "n4", "f4", hexFrustum );
-
-	// cone
-
-	addLine( "p", "n1", hexCone );
-	addLine( "p", "n2", hexCone );
-	addLine( "p", "n3", hexCone );
-	addLine( "p", "n4", hexCone );
-
-	// up
-
-	addLine( "u1", "u2", hexUp );
-	addLine( "u2", "u3", hexUp );
-	addLine( "u3", "u1", hexUp );
-
-	// target
-
-	addLine( "c", "t", hexTarget );
-	addLine( "p", "c", hexCross );
-
-	// cross
-
-	addLine( "cn1", "cn2", hexCross );
-	addLine( "cn3", "cn4", hexCross );
-
-	addLine( "cf1", "cf2", hexCross );
-	addLine( "cf3", "cf4", hexCross );
-
-	function addLine( a, b, hex ) {
-
-		addPoint( a, hex );
-		addPoint( b, hex );
-
-	}
-
-	function addPoint( id, hex ) {
-
-		geometry.vertices.push( new THREE.Vector3() );
-		geometry.colors.push( new THREE.Color( hex ) );
-
-		if ( pointMap[ id ] === undefined ) {
-
-			pointMap[ id ] = [];
-
-		}
-
-		pointMap[ id ].push( geometry.vertices.length - 1 );
-
-	}
-
-	THREE.Line.call( this, geometry, material, THREE.LinePieces );
-
-	this.camera = camera;
-	this.matrixWorld = camera.matrixWorld;
-	this.matrixAutoUpdate = false;
-
-	this.pointMap = pointMap;
-
-	this.update();
-
-};
-
-THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype );
-
-THREE.CameraHelper.prototype.update = function () {
-
-	var vector = new THREE.Vector3();
-	var camera = new THREE.Camera();
-	var projector = new THREE.Projector();
-
-	return function () {
-
-		var scope = this;
-
-		var w = 1, h = 1;
-
-		// we need just camera projection matrix
-		// world matrix must be identity
-
-		camera.projectionMatrix.copy( this.camera.projectionMatrix );
-
-		// center / target
-
-		setPoint( "c", 0, 0, -1 );
-		setPoint( "t", 0, 0,  1 );
-
-		// near
-
-		setPoint( "n1", -w, -h, -1 );
-		setPoint( "n2",  w, -h, -1 );
-		setPoint( "n3", -w,  h, -1 );
-		setPoint( "n4",  w,  h, -1 );
-
-		// far
-
-		setPoint( "f1", -w, -h, 1 );
-		setPoint( "f2",  w, -h, 1 );
-		setPoint( "f3", -w,  h, 1 );
-		setPoint( "f4",  w,  h, 1 );
-
-		// up
-
-		setPoint( "u1",  w * 0.7, h * 1.1, -1 );
-		setPoint( "u2", -w * 0.7, h * 1.1, -1 );
-		setPoint( "u3",        0, h * 2,   -1 );
-
-		// cross
-
-		setPoint( "cf1", -w,  0, 1 );
-		setPoint( "cf2",  w,  0, 1 );
-		setPoint( "cf3",  0, -h, 1 );
-		setPoint( "cf4",  0,  h, 1 );
-
-		setPoint( "cn1", -w,  0, -1 );
-		setPoint( "cn2",  w,  0, -1 );
-		setPoint( "cn3",  0, -h, -1 );
-		setPoint( "cn4",  0,  h, -1 );
-
-		function setPoint( point, x, y, z ) {
-
-			vector.set( x, y, z );
-			projector.unprojectVector( vector, camera );
-
-			var points = scope.pointMap[ point ];
-
-			if ( points !== undefined ) {
-
-				for ( var i = 0, il = points.length; i < il; i ++ ) {
-
-					scope.geometry.vertices[ points[ i ] ].copy( vector );
-
-				}
-
-			}
-
-		}
-
-		this.geometry.verticesNeedUpdate = true;
-
-	};
-
-}();
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.DirectionalLightHelper = function ( light, sphereSize ) {
-
-	THREE.Object3D.call( this );
-
-	this.matrixAutoUpdate = false;
-
-	this.light = light;
-
-	var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 );
-	var material = new THREE.MeshBasicMaterial( { fog: false, wireframe: true } );
-	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.lightSphere = new THREE.Mesh( geometry, material );
-	this.lightSphere.matrixWorld = this.light.matrixWorld;
-	this.lightSphere.matrixAutoUpdate = false;
-	this.add( this.lightSphere );
-
-	/*
-	this.targetSphere = new THREE.Mesh( geometry, material );
-	this.targetSphere.position = this.light.target.position;
-	this.add( this.targetSphere );
-	*/
-
-	geometry = new THREE.Geometry();
-	geometry.vertices.push( this.light.position );
-	geometry.vertices.push( this.light.target.position );
-	geometry.computeLineDistances();
-
-	material = new THREE.LineDashedMaterial( { dashSize: 4, gapSize: 4, opacity: 0.75, transparent: true, fog: false } );
-	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.targetLine = new THREE.Line( geometry, material );
-	this.add( this.targetLine );
-
-}
-
-THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.DirectionalLightHelper.prototype.update = function () {
-
-	this.lightSphere.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.targetLine.geometry.computeLineDistances();
-	this.targetLine.geometry.verticesNeedUpdate = true;
-	this.targetLine.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-};
-
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.GridHelper = function ( size, step ) {
-
-	var geometry = new THREE.Geometry();
-	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
-	var color1 = new THREE.Color( 0x444444 ), color2 = new THREE.Color( 0x888888 );
-
-	for ( var i = - size; i <= size; i += step ) {
-
-		geometry.vertices.push( new THREE.Vector3( -size, 0, i ) );
-		geometry.vertices.push( new THREE.Vector3(  size, 0, i ) );
-
-		geometry.vertices.push( new THREE.Vector3( i, 0, -size ) );
-		geometry.vertices.push( new THREE.Vector3( i, 0,  size ) );
-
-		var color = i === 0 ? color1 : color2;
-
-		geometry.colors.push( color, color, color, color );
-
-	}
-
-	THREE.Line.call( this, geometry, material, THREE.LinePieces );
-
-};
-
-THREE.GridHelper.prototype = Object.create( THREE.Line.prototype );
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) {
-
-	THREE.Object3D.call( this );
-
-	this.light = light;
-
-	var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 );
-	geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
-
-	for ( var i = 0, il = 8; i < il; i ++ ) {
-
-		geometry.faces[ i ].materialIndex = i < 4 ? 0 : 1;
-
-	}
-
-	var materialSky = new THREE.MeshBasicMaterial( { fog: false, wireframe: true } );
-	materialSky.color.copy( light.color ).multiplyScalar( light.intensity );
-
-	var materialGround = new THREE.MeshBasicMaterial( { fog: false, wireframe: true } );
-	materialGround.color.copy( light.groundColor ).multiplyScalar( light.intensity );
-
-	this.lightSphere = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( [ materialSky, materialGround ] ) );
-	this.lightSphere.position = light.position;
-	this.lightSphere.lookAt( new THREE.Vector3() );
-	this.add( this.lightSphere );
-
-};
-
-THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.HemisphereLightHelper.prototype.update = function () {
-
-	this.lightSphere.lookAt( new THREE.Vector3() );
-
-	this.lightSphere.material.materials[ 0 ].color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-	this.lightSphere.material.materials[ 1 ].color.copy( this.light.groundColor ).multiplyScalar( this.light.intensity );
-
-};
-
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.PointLightHelper = function ( light, sphereSize ) {
-
-	THREE.Object3D.call( this );
-
-	this.matrixAutoUpdate = false;
-
-	this.light = light;
-
-	var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 );
-	var material = new THREE.MeshBasicMaterial( { fog: false, wireframe: true } );
-	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.lightSphere = new THREE.Mesh( geometry, material );
-	this.lightSphere.matrixWorld = this.light.matrixWorld;
-	this.lightSphere.matrixAutoUpdate = false;
-	this.add( this.lightSphere );
-
-	/*
-	var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
-	var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
-
-	this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
-	this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
-
-	var d = light.distance;
-
-	if ( d === 0.0 ) {
-
-		this.lightDistance.visible = false;
-
-	} else {
-
-		this.lightDistance.scale.set( d, d, d );
-
-	}
-
-	this.add( this.lightDistance );
-	*/
-
-};
-
-THREE.PointLightHelper.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.PointLightHelper.prototype.update = function () {
-
-	this.lightSphere.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	/*
-	this.lightDistance.material.color.copy( this.color );
-
-	var d = this.light.distance;
-
-	if ( d === 0.0 ) {
-
-		this.lightDistance.visible = false;
-
-	} else {
-
-		this.lightDistance.visible = true;
-		this.lightDistance.scale.set( d, d, d );
-
-	}
-	*/
-
-};
-
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author WestLangley / http://github.com/WestLangley
-*/
-
-THREE.SpotLightHelper = function ( light, sphereSize ) {
-
-	THREE.Object3D.call( this );
-
-	this.matrixAutoUpdate = false;
-
-	this.light = light;
-
-	var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 );
-	var material = new THREE.MeshBasicMaterial( { fog: false, wireframe: true } );
-	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.lightSphere = new THREE.Mesh( geometry, material );
-	this.lightSphere.matrixWorld = this.light.matrixWorld;
-	this.lightSphere.matrixAutoUpdate = false;
-	this.add( this.lightSphere );
-
-	geometry = new THREE.CylinderGeometry( 0.0001, 1, 1, 8, 1, true );
-	geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) );
-	geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
-
-	material = new THREE.MeshBasicMaterial( { fog: false, wireframe: true, opacity: 0.3, transparent: true } );
-	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-	this.lightCone = new THREE.Mesh( geometry, material );
-	this.lightCone.position = this.light.position;
-
-	var coneLength = light.distance ? light.distance : 10000;
-	var coneWidth = coneLength * Math.tan( light.angle );
-
-	this.lightCone.scale.set( coneWidth, coneWidth, coneLength );
-	this.lightCone.lookAt( this.light.target.position );
-
-	this.add( this.lightCone );
-
-};
-
-THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.SpotLightHelper.prototype.update = function () {
-
-	var coneLength = this.light.distance ? this.light.distance : 10000;
-	var coneWidth = coneLength * Math.tan( this.light.angle );
-
-	this.lightCone.scale.set( coneWidth, coneWidth, coneLength );
-	this.lightCone.lookAt( this.light.target.position );
-
-	this.lightSphere.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-	this.lightCone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.ImmediateRenderObject = function () {
-
-	THREE.Object3D.call( this );
-
-	this.render = function ( renderCallback ) { };
-
-};
-
-THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype );
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.LensFlare = function ( texture, size, distance, blending, color ) {
-
-	THREE.Object3D.call( this );
-
-	this.lensFlares = [];
-
-	this.positionScreen = new THREE.Vector3();
-	this.customUpdateCallback = undefined;
-
-	if( texture !== undefined ) {
-
-		this.add( texture, size, distance, blending, color );
-
-	}
-
-};
-
-THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype );
-
-
-/*
- * Add: adds another flare
- */
-
-THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) {
-
-	if( size === undefined ) size = -1;
-	if( distance === undefined ) distance = 0;
-	if( opacity === undefined ) opacity = 1;
-	if( color === undefined ) color = new THREE.Color( 0xffffff );
-	if( blending === undefined ) blending = THREE.NormalBlending;
-
-	distance = Math.min( distance, Math.max( 0, distance ) );
-
-	this.lensFlares.push( { texture: texture, 			// THREE.Texture
-		                    size: size, 				// size in pixels (-1 = use texture.width)
-		                    distance: distance, 		// distance (0-1) from light source (0=at light source)
-		                    x: 0, y: 0, z: 0,			// screen position (-1 => 1) z = 0 is ontop z = 1 is back
-		                    scale: 1, 					// scale
-		                    rotation: 1, 				// rotation
-		                    opacity: opacity,			// opacity
-							color: color,				// color
-		                    blending: blending } );		// blending
-
-};
-
-
-/*
- * Update lens flares update positions on all flares based on the screen position
- * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.
- */
-
-THREE.LensFlare.prototype.updateLensFlares = function () {
-
-	var f, fl = this.lensFlares.length;
-	var flare;
-	var vecX = -this.positionScreen.x * 2;
-	var vecY = -this.positionScreen.y * 2;
-
-	for( f = 0; f < fl; f ++ ) {
-
-		flare = this.lensFlares[ f ];
-
-		flare.x = this.positionScreen.x + vecX * flare.distance;
-		flare.y = this.positionScreen.y + vecY * flare.distance;
-
-		flare.wantedRotation = flare.x * Math.PI * 0.25;
-		flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;
-
-	}
-
-};
-
-
-
-
-
-
-
-
-
-
-
-
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.MorphBlendMesh = function( geometry, material ) {
-
-	THREE.Mesh.call( this, geometry, material );
-
-	this.animationsMap = {};
-	this.animationsList = [];
-
-	// prepare default animation
-	// (all frames played together in 1 second)
-
-	var numFrames = this.geometry.morphTargets.length;
-
-	var name = "__default";
-
-	var startFrame = 0;
-	var endFrame = numFrames - 1;
-
-	var fps = numFrames / 1;
-
-	this.createAnimation( name, startFrame, endFrame, fps );
-	this.setAnimationWeight( name, 1 );
-
-};
-
-THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype );
-
-THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) {
-
-	var animation = {
-
-		startFrame: start,
-		endFrame: end,
-
-		length: end - start + 1,
-
-		fps: fps,
-		duration: ( end - start ) / fps,
-
-		lastFrame: 0,
-		currentFrame: 0,
-
-		active: false,
-
-		time: 0,
-		direction: 1,
-		weight: 1,
-
-		directionBackwards: false,
-		mirroredLoop: false
-
-	};
-
-	this.animationsMap[ name ] = animation;
-	this.animationsList.push( animation );
-
-};
-
-THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {
-
-	var pattern = /([a-z]+)(\d+)/;
-
-	var firstAnimation, frameRanges = {};
-
-	var geometry = this.geometry;
-
-	for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {
-
-		var morph = geometry.morphTargets[ i ];
-		var chunks = morph.name.match( pattern );
-
-		if ( chunks && chunks.length > 1 ) {
-
-			var name = chunks[ 1 ];
-			var num = chunks[ 2 ];
-
-			if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity };
-
-			var range = frameRanges[ name ];
-
-			if ( i < range.start ) range.start = i;
-			if ( i > range.end ) range.end = i;
-
-			if ( ! firstAnimation ) firstAnimation = name;
-
-		}
-
-	}
-
-	for ( var name in frameRanges ) {
-
-		var range = frameRanges[ name ];
-		this.createAnimation( name, range.start, range.end, fps );
-
-	}
-
-	this.firstAnimation = firstAnimation;
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.direction = 1;
-		animation.directionBackwards = false;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.direction = -1;
-		animation.directionBackwards = true;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.fps = fps;
-		animation.duration = ( animation.end - animation.start ) / animation.fps;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.duration = duration;
-		animation.fps = ( animation.end - animation.start ) / animation.duration;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.weight = weight;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.time = time;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) {
-
-	var time = 0;
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		time = animation.time;
-
-	}
-
-	return time;
-
-};
-
-THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) {
-
-	var duration = -1;
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		duration = animation.duration;
-
-	}
-
-	return duration;
-
-};
-
-THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.time = 0;
-		animation.active = true;
-
-	} else {
-
-		console.warn( "animation[" + name + "] undefined" );
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) {
-
-	var animation = this.animationsMap[ name ];
-
-	if ( animation ) {
-
-		animation.active = false;
-
-	}
-
-};
-
-THREE.MorphBlendMesh.prototype.update = function ( delta ) {
-
-	for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {
-
-		var animation = this.animationsList[ i ];
-
-		if ( ! animation.active ) continue;
-
-		var frameTime = animation.duration / animation.length;
-
-		animation.time += animation.direction * delta;
-
-		if ( animation.mirroredLoop ) {
-
-			if ( animation.time > animation.duration || animation.time < 0 ) {
-
-				animation.direction *= -1;
-
-				if ( animation.time > animation.duration ) {
-
-					animation.time = animation.duration;
-					animation.directionBackwards = true;
-
-				}
-
-				if ( animation.time < 0 ) {
-
-					animation.time = 0;
-					animation.directionBackwards = false;
-
-				}
-
-			}
-
-		} else {
-
-			animation.time = animation.time % animation.duration;
-
-			if ( animation.time < 0 ) animation.time += animation.duration;
-
-		}
-
-		var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
-		var weight = animation.weight;
-
-		if ( keyframe !== animation.currentFrame ) {
-
-			this.morphTargetInfluences[ animation.lastFrame ] = 0;
-			this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;
-
-			this.morphTargetInfluences[ keyframe ] = 0;
-
-			animation.lastFrame = animation.currentFrame;
-			animation.currentFrame = keyframe;
-
-		}
-
-		var mix = ( animation.time % frameTime ) / frameTime;
-
-		if ( animation.directionBackwards ) mix = 1 - mix;
-
-		this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
-		this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;
-
-	}
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.LensFlarePlugin = function () {
-
-	var _gl, _renderer, _precision, _lensFlare = {};
-
-	this.init = function ( renderer ) {
-
-		_gl = renderer.context;
-		_renderer = renderer;
-
-		_precision = renderer.getPrecision();
-
-		_lensFlare.vertices = new Float32Array( 8 + 8 );
-		_lensFlare.faces = new Uint16Array( 6 );
-
-		var i = 0;
-		_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1;	// vertex
-		_lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 0;	// uv... etc.
-
-		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = -1;
-		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 0;
-
-		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;
-		_lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;
-
-		_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1;
-		_lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 1;
-
-		i = 0;
-		_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2;
-		_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3;
-
-		// buffers
-
-		_lensFlare.vertexBuffer     = _gl.createBuffer();
-		_lensFlare.elementBuffer    = _gl.createBuffer();
-
-		_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
-		_gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW );
-
-		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
-		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW );
-
-		// textures
-
-		_lensFlare.tempTexture      = _gl.createTexture();
-		_lensFlare.occlusionTexture = _gl.createTexture();
-
-		_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
-		_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
-
-		_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
-		_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
-		_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
-
-		if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) {
-
-			_lensFlare.hasVertexTexture = false;
-			_lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision );
-
-		} else {
-
-			_lensFlare.hasVertexTexture = true;
-			_lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision );
-
-		}
-
-		_lensFlare.attributes = {};
-		_lensFlare.uniforms = {};
-
-		_lensFlare.attributes.vertex       = _gl.getAttribLocation ( _lensFlare.program, "position" );
-		_lensFlare.attributes.uv           = _gl.getAttribLocation ( _lensFlare.program, "uv" );
-
-		_lensFlare.uniforms.renderType     = _gl.getUniformLocation( _lensFlare.program, "renderType" );
-		_lensFlare.uniforms.map            = _gl.getUniformLocation( _lensFlare.program, "map" );
-		_lensFlare.uniforms.occlusionMap   = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" );
-		_lensFlare.uniforms.opacity        = _gl.getUniformLocation( _lensFlare.program, "opacity" );
-		_lensFlare.uniforms.color          = _gl.getUniformLocation( _lensFlare.program, "color" );
-		_lensFlare.uniforms.scale          = _gl.getUniformLocation( _lensFlare.program, "scale" );
-		_lensFlare.uniforms.rotation       = _gl.getUniformLocation( _lensFlare.program, "rotation" );
-		_lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" );
-
-	};
-
-
-	/*
-	 * Render lens flares
-	 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
-	 *         reads these back and calculates occlusion.
-	 *         Then _lensFlare.update_lensFlares() is called to re-position and
-	 *         update transparency of flares. Then they are rendered.
-	 *
-	 */
-
-	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
-
-		var flares = scene.__webglFlares,
-			nFlares = flares.length;
-
-		if ( ! nFlares ) return;
-
-		var tempPosition = new THREE.Vector3();
-
-		var invAspect = viewportHeight / viewportWidth,
-			halfViewportWidth = viewportWidth * 0.5,
-			halfViewportHeight = viewportHeight * 0.5;
-
-		var size = 16 / viewportHeight,
-			scale = new THREE.Vector2( size * invAspect, size );
-
-		var screenPosition = new THREE.Vector3( 1, 1, 0 ),
-			screenPositionPixels = new THREE.Vector2( 1, 1 );
-
-		var uniforms = _lensFlare.uniforms,
-			attributes = _lensFlare.attributes;
-
-		// set _lensFlare program and reset blending
-
-		_gl.useProgram( _lensFlare.program );
-
-		_gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
-		_gl.enableVertexAttribArray( _lensFlare.attributes.uv );
-
-		// loop through all lens flares to update their occlusion and positions
-		// setup gl and common used attribs/unforms
-
-		_gl.uniform1i( uniforms.occlusionMap, 0 );
-		_gl.uniform1i( uniforms.map, 1 );
-
-		_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
-		_gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 );
-		_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
-
-		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
-
-		_gl.disable( _gl.CULL_FACE );
-		_gl.depthMask( false );
-
-		var i, j, jl, flare, sprite;
-
-		for ( i = 0; i < nFlares; i ++ ) {
-
-			size = 16 / viewportHeight;
-			scale.set( size * invAspect, size );
-
-			// calc object screen position
-
-			flare = flares[ i ];
-
-			tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );
-
-			tempPosition.applyMatrix4( camera.matrixWorldInverse );
-			tempPosition.applyProjection( camera.projectionMatrix );
-
-			// setup arrays for gl programs
-
-			screenPosition.copy( tempPosition )
-
-			screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;
-			screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;
-
-			// screen cull
-
-			if ( _lensFlare.hasVertexTexture || (
-				screenPositionPixels.x > 0 &&
-				screenPositionPixels.x < viewportWidth &&
-				screenPositionPixels.y > 0 &&
-				screenPositionPixels.y < viewportHeight ) ) {
-
-				// save current RGB to temp texture
-
-				_gl.activeTexture( _gl.TEXTURE1 );
-				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
-				_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
-
-
-				// render pink quad
-
-				_gl.uniform1i( uniforms.renderType, 0 );
-				_gl.uniform2f( uniforms.scale, scale.x, scale.y );
-				_gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
-
-				_gl.disable( _gl.BLEND );
-				_gl.enable( _gl.DEPTH_TEST );
-
-				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
-
-
-				// copy result to occlusionMap
-
-				_gl.activeTexture( _gl.TEXTURE0 );
-				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
-				_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
-
-
-				// restore graphics
-
-				_gl.uniform1i( uniforms.renderType, 1 );
-				_gl.disable( _gl.DEPTH_TEST );
-
-				_gl.activeTexture( _gl.TEXTURE1 );
-				_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
-				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
-
-
-				// update object positions
-
-				flare.positionScreen.copy( screenPosition )
-
-				if ( flare.customUpdateCallback ) {
-
-					flare.customUpdateCallback( flare );
-
-				} else {
-
-					flare.updateLensFlares();
-
-				}
-
-				// render flares
-
-				_gl.uniform1i( uniforms.renderType, 2 );
-				_gl.enable( _gl.BLEND );
-
-				for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
-
-					sprite = flare.lensFlares[ j ];
-
-					if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
-
-						screenPosition.x = sprite.x;
-						screenPosition.y = sprite.y;
-						screenPosition.z = sprite.z;
-
-						size = sprite.size * sprite.scale / viewportHeight;
-
-						scale.x = size * invAspect;
-						scale.y = size;
-
-						_gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
-						_gl.uniform2f( uniforms.scale, scale.x, scale.y );
-						_gl.uniform1f( uniforms.rotation, sprite.rotation );
-
-						_gl.uniform1f( uniforms.opacity, sprite.opacity );
-						_gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
-
-						_renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
-						_renderer.setTexture( sprite.texture, 1 );
-
-						_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
-
-					}
-
-				}
-
-			}
-
-		}
-
-		// restore gl
-
-		_gl.enable( _gl.CULL_FACE );
-		_gl.enable( _gl.DEPTH_TEST );
-		_gl.depthMask( true );
-
-	};
-
-	function createProgram ( shader, precision ) {
-
-		var program = _gl.createProgram();
-
-		var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
-		var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
-
-		var prefix = "precision " + precision + " float;\n";
-
-		_gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
-		_gl.shaderSource( vertexShader, prefix + shader.vertexShader );
-
-		_gl.compileShader( fragmentShader );
-		_gl.compileShader( vertexShader );
-
-		_gl.attachShader( program, fragmentShader );
-		_gl.attachShader( program, vertexShader );
-
-		_gl.linkProgram( program );
-
-		return program;
-
-	};
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.ShadowMapPlugin = function () {
-
-	var _gl,
-	_renderer,
-	_depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
-
-	_frustum = new THREE.Frustum(),
-	_projScreenMatrix = new THREE.Matrix4(),
-
-	_min = new THREE.Vector3(),
-	_max = new THREE.Vector3(),
-
-	_matrixPosition = new THREE.Vector3();
-
-	this.init = function ( renderer ) {
-
-		_gl = renderer.context;
-		_renderer = renderer;
-
-		var depthShader = THREE.ShaderLib[ "depthRGBA" ];
-		var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
-
-		_depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
-		_depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
-		_depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
-		_depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );
-
-		_depthMaterial._shadowPass = true;
-		_depthMaterialMorph._shadowPass = true;
-		_depthMaterialSkin._shadowPass = true;
-		_depthMaterialMorphSkin._shadowPass = true;
-
-	};
-
-	this.render = function ( scene, camera ) {
-
-		if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return;
-
-		this.update( scene, camera );
-
-	};
-
-	this.update = function ( scene, camera ) {
-
-		var i, il, j, jl, n,
-
-		shadowMap, shadowMatrix, shadowCamera,
-		program, buffer, material,
-		webglObject, object, light,
-		renderList,
-
-		lights = [],
-		k = 0,
-
-		fog = null;
-
-		// set GL state for depth map
-
-		_gl.clearColor( 1, 1, 1, 1 );
-		_gl.disable( _gl.BLEND );
-
-		_gl.enable( _gl.CULL_FACE );
-		_gl.frontFace( _gl.CCW );
-
-		if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
-
-			_gl.cullFace( _gl.FRONT );
-
-		} else {
-
-			_gl.cullFace( _gl.BACK );
-
-		}
-
-		_renderer.setDepthTest( true );
-
-		// preprocess lights
-		// 	- skip lights that are not casting shadows
-		//	- create virtual lights for cascaded shadow maps
-
-		for ( i = 0, il = scene.__lights.length; i < il; i ++ ) {
-
-			light = scene.__lights[ i ];
-
-			if ( ! light.castShadow ) continue;
-
-			if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {
-
-				for ( n = 0; n < light.shadowCascadeCount; n ++ ) {
-
-					var virtualLight;
-
-					if ( ! light.shadowCascadeArray[ n ] ) {
-
-						virtualLight = createVirtualLight( light, n );
-						virtualLight.originalCamera = camera;
-
-						var gyro = new THREE.Gyroscope();
-						gyro.position = light.shadowCascadeOffset;
-
-						gyro.add( virtualLight );
-						gyro.add( virtualLight.target );
-
-						camera.add( gyro );
-
-						light.shadowCascadeArray[ n ] = virtualLight;
-
-						console.log( "Created virtualLight", virtualLight );
-
-					} else {
-
-						virtualLight = light.shadowCascadeArray[ n ];
-
-					}
-
-					updateVirtualLight( light, n );
-
-					lights[ k ] = virtualLight;
-					k ++;
-
-				}
-
-			} else {
-
-				lights[ k ] = light;
-				k ++;
-
-			}
-
-		}
-
-		// render depth map
-
-		for ( i = 0, il = lights.length; i < il; i ++ ) {
-
-			light = lights[ i ];
-
-			if ( ! light.shadowMap ) {
-
-				var shadowFilter = THREE.LinearFilter;
-
-				if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) {
-
-					shadowFilter = THREE.NearestFilter;
-
-				}
-
-				var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
-
-				light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
-				light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
-
-				light.shadowMatrix = new THREE.Matrix4();
-
-			}
-
-			if ( ! light.shadowCamera ) {
-
-				if ( light instanceof THREE.SpotLight ) {
-
-					light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
-
-				} else if ( light instanceof THREE.DirectionalLight ) {
-
-					light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );
-
-				} else {
-
-					console.error( "Unsupported light type for shadow" );
-					continue;
-
-				}
-
-				scene.add( light.shadowCamera );
-
-				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-
-			}
-
-			if ( light.shadowCameraVisible && ! light.cameraHelper ) {
-
-				light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
-				light.shadowCamera.add( light.cameraHelper );
-
-			}
-
-			if ( light.isVirtual && virtualLight.originalCamera == camera ) {
-
-				updateShadowCamera( camera, light );
-
-			}
-
-			shadowMap = light.shadowMap;
-			shadowMatrix = light.shadowMatrix;
-			shadowCamera = light.shadowCamera;
-
-			shadowCamera.position.getPositionFromMatrix( light.matrixWorld );
-			_matrixPosition.getPositionFromMatrix( light.target.matrixWorld );
-			shadowCamera.lookAt( _matrixPosition );
-			shadowCamera.updateMatrixWorld();
-
-			shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
-
-			if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
-			if ( light.shadowCameraVisible ) light.cameraHelper.update();
-
-			// compute shadow matrix
-
-			shadowMatrix.set( 0.5, 0.0, 0.0, 0.5,
-							  0.0, 0.5, 0.0, 0.5,
-							  0.0, 0.0, 0.5, 0.5,
-							  0.0, 0.0, 0.0, 1.0 );
-
-			shadowMatrix.multiply( shadowCamera.projectionMatrix );
-			shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
-
-			// update camera matrices and frustum
-
-			_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
-			_frustum.setFromMatrix( _projScreenMatrix );
-
-			// render shadow map
-
-			_renderer.setRenderTarget( shadowMap );
-			_renderer.clear();
-
-			// set object matrices & frustum culling
-
-			renderList = scene.__webglObjects;
-
-			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-				webglObject = renderList[ j ];
-				object = webglObject.object;
-
-				webglObject.render = false;
-
-				if ( object.visible && object.castShadow ) {
-
-					if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
-
-						object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
-
-						webglObject.render = true;
-
-					}
-
-				}
-
-			}
-
-			// render regular objects
-
-			var objectMaterial, useMorphing, useSkinning;
-
-			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-				webglObject = renderList[ j ];
-
-				if ( webglObject.render ) {
-
-					object = webglObject.object;
-					buffer = webglObject.buffer;
-
-					// culling is overriden globally for all objects
-					// while rendering depth map
-
-					// need to deal with MeshFaceMaterial somehow
-					// in that case just use the first of material.materials for now
-					// (proper solution would require to break objects by materials
-					//  similarly to regular rendering and then set corresponding
-					//  depth materials per each chunk instead of just once per object)
-
-					objectMaterial = getObjectMaterial( object );
-
-					useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
-					useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
-
-					if ( object.customDepthMaterial ) {
-
-						material = object.customDepthMaterial;
-
-					} else if ( useSkinning ) {
-
-						material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
-
-					} else if ( useMorphing ) {
-
-						material = _depthMaterialMorph;
-
-					} else {
-
-						material = _depthMaterial;
-
-					}
-
-					if ( buffer instanceof THREE.BufferGeometry ) {
-
-						_renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );
-
-					} else {
-
-						_renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );
-
-					}
-
-				}
-
-			}
-
-			// set matrices and render immediate objects
-
-			renderList = scene.__webglObjectsImmediate;
-
-			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-				webglObject = renderList[ j ];
-				object = webglObject.object;
-
-				if ( object.visible && object.castShadow ) {
-
-					object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
-
-					_renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object );
-
-				}
-
-			}
-
-		}
-
-		// restore GL state
-
-		var clearColor = _renderer.getClearColor(),
-		clearAlpha = _renderer.getClearAlpha();
-
-		_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
-		_gl.enable( _gl.BLEND );
-
-		if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
-
-			_gl.cullFace( _gl.BACK );
-
-		}
-
-	};
-
-	function createVirtualLight( light, cascade ) {
-
-		var virtualLight = new THREE.DirectionalLight();
-
-		virtualLight.isVirtual = true;
-
-		virtualLight.onlyShadow = true;
-		virtualLight.castShadow = true;
-
-		virtualLight.shadowCameraNear = light.shadowCameraNear;
-		virtualLight.shadowCameraFar = light.shadowCameraFar;
-
-		virtualLight.shadowCameraLeft = light.shadowCameraLeft;
-		virtualLight.shadowCameraRight = light.shadowCameraRight;
-		virtualLight.shadowCameraBottom = light.shadowCameraBottom;
-		virtualLight.shadowCameraTop = light.shadowCameraTop;
-
-		virtualLight.shadowCameraVisible = light.shadowCameraVisible;
-
-		virtualLight.shadowDarkness = light.shadowDarkness;
-
-		virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
-		virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];
-		virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];
-
-		virtualLight.pointsWorld = [];
-		virtualLight.pointsFrustum = [];
-
-		var pointsWorld = virtualLight.pointsWorld,
-			pointsFrustum = virtualLight.pointsFrustum;
-
-		for ( var i = 0; i < 8; i ++ ) {
-
-			pointsWorld[ i ] = new THREE.Vector3();
-			pointsFrustum[ i ] = new THREE.Vector3();
-
-		}
-
-		var nearZ = light.shadowCascadeNearZ[ cascade ];
-		var farZ = light.shadowCascadeFarZ[ cascade ];
-
-		pointsFrustum[ 0 ].set( -1, -1, nearZ );
-		pointsFrustum[ 1 ].set(  1, -1, nearZ );
-		pointsFrustum[ 2 ].set( -1,  1, nearZ );
-		pointsFrustum[ 3 ].set(  1,  1, nearZ );
-
-		pointsFrustum[ 4 ].set( -1, -1, farZ );
-		pointsFrustum[ 5 ].set(  1, -1, farZ );
-		pointsFrustum[ 6 ].set( -1,  1, farZ );
-		pointsFrustum[ 7 ].set(  1,  1, farZ );
-
-		return virtualLight;
-
-	}
-
-	// Synchronize virtual light with the original light
-
-	function updateVirtualLight( light, cascade ) {
-
-		var virtualLight = light.shadowCascadeArray[ cascade ];
-
-		virtualLight.position.copy( light.position );
-		virtualLight.target.position.copy( light.target.position );
-		virtualLight.lookAt( virtualLight.target );
-
-		virtualLight.shadowCameraVisible = light.shadowCameraVisible;
-		virtualLight.shadowDarkness = light.shadowDarkness;
-
-		virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
-
-		var nearZ = light.shadowCascadeNearZ[ cascade ];
-		var farZ = light.shadowCascadeFarZ[ cascade ];
-
-		var pointsFrustum = virtualLight.pointsFrustum;
-
-		pointsFrustum[ 0 ].z = nearZ;
-		pointsFrustum[ 1 ].z = nearZ;
-		pointsFrustum[ 2 ].z = nearZ;
-		pointsFrustum[ 3 ].z = nearZ;
-
-		pointsFrustum[ 4 ].z = farZ;
-		pointsFrustum[ 5 ].z = farZ;
-		pointsFrustum[ 6 ].z = farZ;
-		pointsFrustum[ 7 ].z = farZ;
-
-	}
-
-	// Fit shadow camera's ortho frustum to camera frustum
-
-	function updateShadowCamera( camera, light ) {
-
-		var shadowCamera = light.shadowCamera,
-			pointsFrustum = light.pointsFrustum,
-			pointsWorld = light.pointsWorld;
-
-		_min.set( Infinity, Infinity, Infinity );
-		_max.set( -Infinity, -Infinity, -Infinity );
-
-		for ( var i = 0; i < 8; i ++ ) {
-
-			var p = pointsWorld[ i ];
-
-			p.copy( pointsFrustum[ i ] );
-			THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera );
-
-			p.applyMatrix4( shadowCamera.matrixWorldInverse );
-
-			if ( p.x < _min.x ) _min.x = p.x;
-			if ( p.x > _max.x ) _max.x = p.x;
-
-			if ( p.y < _min.y ) _min.y = p.y;
-			if ( p.y > _max.y ) _max.y = p.y;
-
-			if ( p.z < _min.z ) _min.z = p.z;
-			if ( p.z > _max.z ) _max.z = p.z;
-
-		}
-
-		shadowCamera.left = _min.x;
-		shadowCamera.right = _max.x;
-		shadowCamera.top = _max.y;
-		shadowCamera.bottom = _min.y;
-
-		// can't really fit near/far
-		//shadowCamera.near = _min.z;
-		//shadowCamera.far = _max.z;
-
-		shadowCamera.updateProjectionMatrix();
-
-	}
-
-	// For the moment just ignore objects that have multiple materials with different animation methods
-	// Only the first material will be taken into account for deciding which depth material to use for shadow maps
-
-	function getObjectMaterial( object ) {
-
-		return object.material instanceof THREE.MeshFaceMaterial
-			? object.material.materials[ 0 ]
-			: object.material;
-
-	};
-
-};
-
-THREE.ShadowMapPlugin.__projector = new THREE.Projector();
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SpritePlugin = function () {
-
-	var _gl, _renderer, _precision, _sprite = {};
-
-	this.init = function ( renderer ) {
-
-		_gl = renderer.context;
-		_renderer = renderer;
-
-		_precision = renderer.getPrecision();
-
-		_sprite.vertices = new Float32Array( 8 + 8 );
-		_sprite.faces    = new Uint16Array( 6 );
-
-		var i = 0;
-
-		_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1;	// vertex 0
-		_sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 0;	// uv 0
-
-		_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = -1;	// vertex 1
-		_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 0;	// uv 1
-
-		_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;	// vertex 2
-		_sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;	// uv 2
-
-		_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1;	// vertex 3
-		_sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 1;	// uv 3
-
-		i = 0;
-
-		_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2;
-		_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3;
-
-		_sprite.vertexBuffer  = _gl.createBuffer();
-		_sprite.elementBuffer = _gl.createBuffer();
-
-		_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
-		_gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW );
-
-		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
-		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW );
-
-		_sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ], _precision );
-
-		_sprite.attributes = {};
-		_sprite.uniforms = {};
-
-		_sprite.attributes.position           = _gl.getAttribLocation ( _sprite.program, "position" );
-		_sprite.attributes.uv                 = _gl.getAttribLocation ( _sprite.program, "uv" );
-
-		_sprite.uniforms.uvOffset             = _gl.getUniformLocation( _sprite.program, "uvOffset" );
-		_sprite.uniforms.uvScale              = _gl.getUniformLocation( _sprite.program, "uvScale" );
-
-		_sprite.uniforms.rotation             = _gl.getUniformLocation( _sprite.program, "rotation" );
-		_sprite.uniforms.scale                = _gl.getUniformLocation( _sprite.program, "scale" );
-		_sprite.uniforms.alignment            = _gl.getUniformLocation( _sprite.program, "alignment" );
-
-		_sprite.uniforms.color                = _gl.getUniformLocation( _sprite.program, "color" );
-		_sprite.uniforms.map                  = _gl.getUniformLocation( _sprite.program, "map" );
-		_sprite.uniforms.opacity              = _gl.getUniformLocation( _sprite.program, "opacity" );
-
-		_sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" );
-		_sprite.uniforms.sizeAttenuation   	  = _gl.getUniformLocation( _sprite.program, "sizeAttenuation" );
-		_sprite.uniforms.screenPosition    	  = _gl.getUniformLocation( _sprite.program, "screenPosition" );
-		_sprite.uniforms.modelViewMatrix      = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" );
-		_sprite.uniforms.projectionMatrix     = _gl.getUniformLocation( _sprite.program, "projectionMatrix" );
-
-		_sprite.uniforms.fogType 		  	  = _gl.getUniformLocation( _sprite.program, "fogType" );
-		_sprite.uniforms.fogDensity 		  = _gl.getUniformLocation( _sprite.program, "fogDensity" );
-		_sprite.uniforms.fogNear 		  	  = _gl.getUniformLocation( _sprite.program, "fogNear" );
-		_sprite.uniforms.fogFar 		  	  = _gl.getUniformLocation( _sprite.program, "fogFar" );
-		_sprite.uniforms.fogColor 		  	  = _gl.getUniformLocation( _sprite.program, "fogColor" );
-
-		_sprite.uniforms.alphaTest 		  	  = _gl.getUniformLocation( _sprite.program, "alphaTest" );
-
-	};
-
-	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
-
-		var sprites = scene.__webglSprites,
-			nSprites = sprites.length;
-
-		if ( ! nSprites ) return;
-
-		var attributes = _sprite.attributes,
-			uniforms = _sprite.uniforms;
-
-		var invAspect = viewportHeight / viewportWidth;
-
-		var halfViewportWidth = viewportWidth * 0.5,
-			halfViewportHeight = viewportHeight * 0.5;
-
-		// setup gl
-
-		_gl.useProgram( _sprite.program );
-
-		_gl.enableVertexAttribArray( attributes.position );
-		_gl.enableVertexAttribArray( attributes.uv );
-
-		_gl.disable( _gl.CULL_FACE );
-		_gl.enable( _gl.BLEND );
-
-		_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
-		_gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
-		_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
-
-		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
-
-		_gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
-
-		_gl.activeTexture( _gl.TEXTURE0 );
-		_gl.uniform1i( uniforms.map, 0 );
-
-		var oldFogType = 0;
-		var sceneFogType = 0;
-		var fog = scene.fog;
-
-		if ( fog ) {
-
-			_gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
-
-			if ( fog instanceof THREE.Fog ) {
-
-				_gl.uniform1f( uniforms.fogNear, fog.near );
-				_gl.uniform1f( uniforms.fogFar, fog.far );
-
-				_gl.uniform1i( uniforms.fogType, 1 );
-				oldFogType = 1;
-				sceneFogType = 1;
-
-			} else if ( fog instanceof THREE.FogExp2 ) {
-
-				_gl.uniform1f( uniforms.fogDensity, fog.density );
-
-				_gl.uniform1i( uniforms.fogType, 2 );
-				oldFogType = 2;
-				sceneFogType = 2;
-
-			}
-
-		} else {
-
-			_gl.uniform1i( uniforms.fogType, 0 );
-			oldFogType = 0;
-			sceneFogType = 0;
-
-		}
-
-
-		// update positions and sort
-
-		var i, sprite, material, screenPosition, size, fogType, scale = [];
-
-		for( i = 0; i < nSprites; i ++ ) {
-
-			sprite = sprites[ i ];
-			material = sprite.material;
-
-			if ( ! sprite.visible || material.opacity === 0 ) continue;
-
-			if ( ! material.useScreenCoordinates ) {
-
-				sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
-				sprite.z = - sprite._modelViewMatrix.elements[ 14 ];
-
-			} else {
-
-				sprite.z = - sprite.position.z;
-
-			}
-
-		}
-
-		sprites.sort( painterSortStable );
-
-		// render all sprites
-
-		for( i = 0; i < nSprites; i ++ ) {
-
-			sprite = sprites[ i ];
-			material = sprite.material;
-
-			if ( ! sprite.visible || material.opacity === 0 ) continue;
-
-			if ( material.map && material.map.image && material.map.image.width ) {
-
-				_gl.uniform1f( uniforms.alphaTest, material.alphaTest );
-
-				if ( material.useScreenCoordinates === true ) {
-
-					_gl.uniform1i( uniforms.useScreenCoordinates, 1 );
-					_gl.uniform3f(
-						uniforms.screenPosition,
-						( ( sprite.position.x * _renderer.devicePixelRatio ) - halfViewportWidth  ) / halfViewportWidth,
-						( halfViewportHeight - ( sprite.position.y * _renderer.devicePixelRatio ) ) / halfViewportHeight,
-						Math.max( 0, Math.min( 1, sprite.position.z ) )
-					);
-
-					scale[ 0 ] = _renderer.devicePixelRatio;
-					scale[ 1 ] = _renderer.devicePixelRatio;
-
-				} else {
-
-					_gl.uniform1i( uniforms.useScreenCoordinates, 0 );
-					_gl.uniform1i( uniforms.sizeAttenuation, material.sizeAttenuation ? 1 : 0 );
-					_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );
-
-					scale[ 0 ] = 1;
-					scale[ 1 ] = 1;
-
-				}
-
-				if ( scene.fog && material.fog ) {
-
-					fogType = sceneFogType;
-
-				} else {
-
-					fogType = 0;
-
-				}
-
-				if ( oldFogType !== fogType ) {
-
-					_gl.uniform1i( uniforms.fogType, fogType );
-					oldFogType = fogType;
-
-				}
-
-				size = 1 / ( material.scaleByViewport ? viewportHeight : 1 );
-
-				scale[ 0 ] *= size * invAspect * sprite.scale.x
-				scale[ 1 ] *= size * sprite.scale.y;
-
-				_gl.uniform2f( uniforms.uvScale, material.uvScale.x, material.uvScale.y );
-				_gl.uniform2f( uniforms.uvOffset, material.uvOffset.x, material.uvOffset.y );
-				_gl.uniform2f( uniforms.alignment, material.alignment.x, material.alignment.y );
-
-				_gl.uniform1f( uniforms.opacity, material.opacity );
-				_gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
-
-				_gl.uniform1f( uniforms.rotation, sprite.rotation );
-				_gl.uniform2fv( uniforms.scale, scale );
-
-				_renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
-				_renderer.setDepthTest( material.depthTest );
-				_renderer.setDepthWrite( material.depthWrite );
-				_renderer.setTexture( material.map, 0 );
-
-				_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
-
-			}
-
-		}
-
-		// restore gl
-
-		_gl.enable( _gl.CULL_FACE );
-
-	};
-
-	function createProgram ( shader, precision ) {
-
-		var program = _gl.createProgram();
-
-		var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
-		var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
-
-		var prefix = "precision " + precision + " float;\n";
-
-		_gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
-		_gl.shaderSource( vertexShader, prefix + shader.vertexShader );
-
-		_gl.compileShader( fragmentShader );
-		_gl.compileShader( vertexShader );
-
-		_gl.attachShader( program, fragmentShader );
-		_gl.attachShader( program, vertexShader );
-
-		_gl.linkProgram( program );
-
-		return program;
-
-	};
-
-	function painterSortStable ( a, b ) {
-
-		if ( a.z !== b.z ) {
-
-			return b.z - a.z;
-
-		} else {
-
-			return b.id - a.id;
-
-		}
-
-	};
-
-};
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.DepthPassPlugin = function () {
-
-	this.enabled = false;
-	this.renderTarget = null;
-
-	var _gl,
-	_renderer,
-	_depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
-
-	_frustum = new THREE.Frustum(),
-	_projScreenMatrix = new THREE.Matrix4();
-
-	this.init = function ( renderer ) {
-
-		_gl = renderer.context;
-		_renderer = renderer;
-
-		var depthShader = THREE.ShaderLib[ "depthRGBA" ];
-		var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
-
-		_depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
-		_depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
-		_depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
-		_depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );
-
-		_depthMaterial._shadowPass = true;
-		_depthMaterialMorph._shadowPass = true;
-		_depthMaterialSkin._shadowPass = true;
-		_depthMaterialMorphSkin._shadowPass = true;
-
-	};
-
-	this.render = function ( scene, camera ) {
-
-		if ( ! this.enabled ) return;
-
-		this.update( scene, camera );
-
-	};
-
-	this.update = function ( scene, camera ) {
-
-		var i, il, j, jl, n,
-
-		program, buffer, material,
-		webglObject, object, light,
-		renderList,
-
-		fog = null;
-
-		// set GL state for depth map
-
-		_gl.clearColor( 1, 1, 1, 1 );
-		_gl.disable( _gl.BLEND );
-
-		_renderer.setDepthTest( true );
-
-		// update scene
-
-		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-
-		// update camera matrices and frustum
-
-		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
-		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
-		_frustum.setFromMatrix( _projScreenMatrix );
-
-		// render depth map
-
-		_renderer.setRenderTarget( this.renderTarget );
-		_renderer.clear();
-
-		// set object matrices & frustum culling
-
-		renderList = scene.__webglObjects;
-
-		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-			webglObject = renderList[ j ];
-			object = webglObject.object;
-
-			webglObject.render = false;
-
-			if ( object.visible ) {
-
-				if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
-
-					object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
-
-					webglObject.render = true;
-
-				}
-
-			}
-
-		}
-
-		// render regular objects
-
-		var objectMaterial, useMorphing, useSkinning;
-
-		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-			webglObject = renderList[ j ];
-
-			if ( webglObject.render ) {
-
-				object = webglObject.object;
-				buffer = webglObject.buffer;
-
-				// todo: create proper depth material for particles
-
-				if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue;
-
-				objectMaterial = getObjectMaterial( object );
-
-				if ( objectMaterial ) _renderer.setMaterialFaces( object.material );
-
-				useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
-				useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
-
-				if ( object.customDepthMaterial ) {
-
-					material = object.customDepthMaterial;
-
-				} else if ( useSkinning ) {
-
-					material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
-
-				} else if ( useMorphing ) {
-
-					material = _depthMaterialMorph;
-
-				} else {
-
-					material = _depthMaterial;
-
-				}
-
-				if ( buffer instanceof THREE.BufferGeometry ) {
-
-					_renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object );
-
-				} else {
-
-					_renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object );
-
-				}
-
-			}
-
-		}
-
-		// set matrices and render immediate objects
-
-		renderList = scene.__webglObjectsImmediate;
-
-		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-			webglObject = renderList[ j ];
-			object = webglObject.object;
-
-			if ( object.visible ) {
-
-				object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
-
-				_renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object );
-
-			}
-
-		}
-
-		// restore GL state
-
-		var clearColor = _renderer.getClearColor(),
-		clearAlpha = _renderer.getClearAlpha();
-
-		_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
-		_gl.enable( _gl.BLEND );
-
-	};
-
-	// For the moment just ignore objects that have multiple materials with different animation methods
-	// Only the first material will be taken into account for deciding which depth material to use
-
-	function getObjectMaterial( object ) {
-
-		return object.material instanceof THREE.MeshFaceMaterial
-			? object.material.materials[ 0 ]
-			: object.material;
-
-	};
-
-};
-
-/**
- * @author mikael emtinger / http://gomo.se/
- *
- */
-
-THREE.ShaderFlares = {
-
-	'lensFlareVertexTexture': {
-
-		vertexShader: [
-
-			"uniform lowp int renderType;",
-
-			"uniform vec3 screenPosition;",
-			"uniform vec2 scale;",
-			"uniform float rotation;",
-
-			"uniform sampler2D occlusionMap;",
-
-			"attribute vec2 position;",
-			"attribute vec2 uv;",
-
-			"varying vec2 vUV;",
-			"varying float vVisibility;",
-
-			"void main() {",
-
-				"vUV = uv;",
-
-				"vec2 pos = position;",
-
-				"if( renderType == 2 ) {",
-
-					"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.5, 0.1 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.9, 0.1 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.9, 0.9 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.1, 0.9 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ) +",
-									  "texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",
-
-					"vVisibility = (       visibility.r / 9.0 ) *",
-								  "( 1.0 - visibility.g / 9.0 ) *",
-								  "(       visibility.b / 9.0 ) *",
-								  "( 1.0 - visibility.a / 9.0 );",
-
-					"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
-					"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
-
-				"}",
-
-				"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
-
-			"}"
-
-		].join( "\n" ),
-
-		fragmentShader: [
-
-			"uniform lowp int renderType;",
-
-			"uniform sampler2D map;",
-			"uniform float opacity;",
-			"uniform vec3 color;",
-
-			"varying vec2 vUV;",
-			"varying float vVisibility;",
-
-			"void main() {",
-
-				// pink square
-
-				"if( renderType == 0 ) {",
-
-					"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",
-
-				// restore
-
-				"} else if( renderType == 1 ) {",
-
-					"gl_FragColor = texture2D( map, vUV );",
-
-				// flare
-
-				"} else {",
-
-					"vec4 texture = texture2D( map, vUV );",
-					"texture.a *= opacity * vVisibility;",
-					"gl_FragColor = texture;",
-					"gl_FragColor.rgb *= color;",
-
-				"}",
-
-			"}"
-		].join( "\n" )
-
-	},
-
-
-	'lensFlare': {
-
-		vertexShader: [
-
-			"uniform lowp int renderType;",
-
-			"uniform vec3 screenPosition;",
-			"uniform vec2 scale;",
-			"uniform float rotation;",
-
-			"attribute vec2 position;",
-			"attribute vec2 uv;",
-
-			"varying vec2 vUV;",
-
-			"void main() {",
-
-				"vUV = uv;",
-
-				"vec2 pos = position;",
-
-				"if( renderType == 2 ) {",
-
-					"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
-					"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
-
-				"}",
-
-				"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
-
-			"}"
-
-		].join( "\n" ),
-
-		fragmentShader: [
-
-			"precision mediump float;",
-
-			"uniform lowp int renderType;",
-
-			"uniform sampler2D map;",
-			"uniform sampler2D occlusionMap;",
-			"uniform float opacity;",
-			"uniform vec3 color;",
-
-			"varying vec2 vUV;",
-
-			"void main() {",
-
-				// pink square
-
-				"if( renderType == 0 ) {",
-
-					"gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );",
-
-				// restore
-
-				"} else if( renderType == 1 ) {",
-
-					"gl_FragColor = texture2D( map, vUV );",
-
-				// flare
-
-				"} else {",
-
-					"float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a +",
-									   "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a +",
-									   "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a +",
-									   "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;",
-
-					"visibility = ( 1.0 - visibility / 4.0 );",
-
-					"vec4 texture = texture2D( map, vUV );",
-					"texture.a *= opacity * visibility;",
-					"gl_FragColor = texture;",
-					"gl_FragColor.rgb *= color;",
-
-				"}",
-
-			"}"
-
-		].join( "\n" )
-
-	}
-
-};
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- *
- */
-
-THREE.ShaderSprite = {
-
-	'sprite': {
-
-		vertexShader: [
-
-			"uniform int useScreenCoordinates;",
-			"uniform int sizeAttenuation;",
-			"uniform vec3 screenPosition;",
-			"uniform mat4 modelViewMatrix;",
-			"uniform mat4 projectionMatrix;",
-			"uniform float rotation;",
-			"uniform vec2 scale;",
-			"uniform vec2 alignment;",
-			"uniform vec2 uvOffset;",
-			"uniform vec2 uvScale;",
-
-			"attribute vec2 position;",
-			"attribute vec2 uv;",
-
-			"varying vec2 vUV;",
-
-			"void main() {",
-
-				"vUV = uvOffset + uv * uvScale;",
-
-				"vec2 alignedPosition = position + alignment;",
-
-				"vec2 rotatedPosition;",
-				"rotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;",
-				"rotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;",
-
-				"vec4 finalPosition;",
-
-				"if( useScreenCoordinates != 0 ) {",
-
-					"finalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );",
-
-				"} else {",
-
-					"finalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );",
-					"finalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );",
-
-				"}",
-
-				"gl_Position = finalPosition;",
-
-			"}"
-
-		].join( "\n" ),
-
-		fragmentShader: [
-
-			"uniform vec3 color;",
-			"uniform sampler2D map;",
-			"uniform float opacity;",
-
-			"uniform int fogType;",
-			"uniform vec3 fogColor;",
-			"uniform float fogDensity;",
-			"uniform float fogNear;",
-			"uniform float fogFar;",
-			"uniform float alphaTest;",
-
-			"varying vec2 vUV;",
-
-			"void main() {",
-
-				"vec4 texture = texture2D( map, vUV );",
-
-				"if ( texture.a < alphaTest ) discard;",
-
-				"gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );",
-
-				"if ( fogType > 0 ) {",
-
-					"float depth = gl_FragCoord.z / gl_FragCoord.w;",
-					"float fogFactor = 0.0;",
-
-					"if ( fogType == 1 ) {",
-
-						"fogFactor = smoothstep( fogNear, fogFar, depth );",
-
-					"} else {",
-
-						"const float LOG2 = 1.442695;",
-						"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
-						"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
-
-					"}",
-
-					"gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
-
-				"}",
-
-			"}"
-
-		].join( "\n" )
-
-	}
-
-};
-
-/**
- * @author Eberhard Graether / http://egraether.com/
- */
-
-THREE.TrackballControls = function ( object, domElement ) {
-
-	var _this = this;
-	var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };
-
-	this.object = object;
-	this.domElement = ( domElement !== undefined ) ? domElement : document;
-
-	// API
-
-	this.enabled = true;
-
-	this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 };
-	this.radius = ( this.screen.width + this.screen.height ) / 4;
-
-	this.rotateSpeed = 1.0;
-	this.zoomSpeed = 1.2;
-	this.panSpeed = 0.3;
-
-	this.noRotate = false;
-	this.noZoom = false;
-	this.noPan = false;
-
-	this.staticMoving = false;
-	this.dynamicDampingFactor = 0.2;
-
-	this.minDistance = 0;
-	this.maxDistance = Infinity;
-
-	this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
-
-	// internals
-
-	this.target = new THREE.Vector3();
-
-	var lastPosition = new THREE.Vector3();
-
-	var _state = STATE.NONE,
-	_prevState = STATE.NONE,
-
-	_eye = new THREE.Vector3(),
-
-	_rotateStart = new THREE.Vector3(),
-	_rotateEnd = new THREE.Vector3(),
-
-	_zoomStart = new THREE.Vector2(),
-	_zoomEnd = new THREE.Vector2(),
-
-	_touchZoomDistanceStart = 0,
-	_touchZoomDistanceEnd = 0,
-
-	_panStart = new THREE.Vector2(),
-	_panEnd = new THREE.Vector2();
-
-	// for reset
-
-	this.target0 = this.target.clone();
-	this.position0 = this.object.position.clone();
-	this.up0 = this.object.up.clone();
-
-	// events
-
-	var changeEvent = { type: 'change' };
-
-
-	// methods
-
-	this.handleResize = function () {
-
-		this.screen.width = window.innerWidth;
-		this.screen.height = window.innerHeight;
-
-		this.screen.offsetLeft = 0;
-		this.screen.offsetTop = 0;
-
-		this.radius = ( this.screen.width + this.screen.height ) / 4;
-
-	};
-
-	this.handleEvent = function ( event ) {
-
-		if ( typeof this[ event.type ] == 'function' ) {
-
-			this[ event.type ]( event );
-
-		}
-
-	};
-
-	this.getMouseOnScreen = function ( clientX, clientY ) {
-
-		return new THREE.Vector2(
-			( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5,
-			( clientY - _this.screen.offsetTop ) / _this.radius * 0.5
-		);
-
-	};
-
-	this.getMouseProjectionOnBall = function ( clientX, clientY ) {
-
-		var mouseOnBall = new THREE.Vector3(
-			( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius,
-			( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius,
-			0.0
-		);
-
-		var length = mouseOnBall.length();
-
-		if ( length > 1.0 ) {
-
-			mouseOnBall.normalize();
-
-		} else {
-
-			mouseOnBall.z = Math.sqrt( 1.0 - length * length );
-
-		}
-
-		_eye.copy( _this.object.position ).sub( _this.target );
-
-		var projection = _this.object.up.clone().setLength( mouseOnBall.y );
-		projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) );
-		projection.add( _eye.setLength( mouseOnBall.z ) );
-
-		return projection;
-
-	};
-
-	this.rotateCamera = function () {
-
-		var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
-
-		if ( angle ) {
-
-			var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(),
-				quaternion = new THREE.Quaternion();
-
-			angle *= _this.rotateSpeed;
-
-			quaternion.setFromAxisAngle( axis, -angle );
-
-			_eye.applyQuaternion( quaternion );
-			_this.object.up.applyQuaternion( quaternion );
-
-			_rotateEnd.applyQuaternion( quaternion );
-
-			if ( _this.staticMoving ) {
-
-				_rotateStart.copy( _rotateEnd );
-
-			} else {
-
-				quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
-				_rotateStart.applyQuaternion( quaternion );
-
-			}
-
-		}
-
-	};
-
-	this.zoomCamera = function () {
-
-		if ( _state === STATE.TOUCH_ZOOM ) {
-
-			var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
-			_touchZoomDistanceStart = _touchZoomDistanceEnd;
-			_eye.multiplyScalar( factor );
-
-		} else {
-
-			var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
-
-			if ( factor !== 1.0 && factor > 0.0 ) {
-
-				_eye.multiplyScalar( factor );
-
-				if ( _this.staticMoving ) {
-
-					_zoomStart.copy( _zoomEnd );
-
-				} else {
-
-					_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
-
-				}
-
-			}
-
-		}
-
-	};
-
-	this.panCamera = function () {
-
-		var mouseChange = _panEnd.clone().sub( _panStart );
-
-		if ( mouseChange.lengthSq() ) {
-
-			mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
-
-			var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x );
-			pan.add( _this.object.up.clone().setLength( mouseChange.y ) );
-
-			_this.object.position.add( pan );
-			_this.target.add( pan );
-
-			if ( _this.staticMoving ) {
-
-				_panStart = _panEnd;
-
-			} else {
-
-				_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
-
-			}
-
-		}
-
-	};
-
-	this.checkDistances = function () {
-
-		if ( !_this.noZoom || !_this.noPan ) {
-
-			if ( _this.object.position.lengthSq() > _this.maxDistance * _this.maxDistance ) {
-
-				_this.object.position.setLength( _this.maxDistance );
-
-			}
-
-			if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
-
-				_this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
-
-			}
-
-		}
-
-	};
-
-	this.update = function () {
-
-		_eye.subVectors( _this.object.position, _this.target );
-
-		if ( !_this.noRotate ) {
-
-			_this.rotateCamera();
-
-		}
-
-		if ( !_this.noZoom ) {
-
-			_this.zoomCamera();
-
-		}
-
-		if ( !_this.noPan ) {
-
-			_this.panCamera();
-
-		}
-
-		_this.object.position.addVectors( _this.target, _eye );
-
-		_this.checkDistances();
-
-		_this.object.lookAt( _this.target );
-
-		if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {
-
-			_this.dispatchEvent( changeEvent );
-
-			lastPosition.copy( _this.object.position );
-
-		}
-
-	};
-
-	this.reset = function () {
-
-		_state = STATE.NONE;
-		_prevState = STATE.NONE;
-
-		_this.target.copy( _this.target0 );
-		_this.object.position.copy( _this.position0 );
-		_this.object.up.copy( _this.up0 );
-
-		_eye.subVectors( _this.object.position, _this.target );
-
-		_this.object.lookAt( _this.target );
-
-		_this.dispatchEvent( changeEvent );
-
-		lastPosition.copy( _this.object.position );
-
-	};
-
-	// listeners
-
-	function keydown( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		window.removeEventListener( 'keydown', keydown );
-
-		_prevState = _state;
-
-		if ( _state !== STATE.NONE ) {
-
-			return;
-
-		} else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {
-
-			_state = STATE.ROTATE;
-
-		} else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {
-
-			_state = STATE.ZOOM;
-
-		} else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {
-
-			_state = STATE.PAN;
-
-		}
-
-	}
-
-	function keyup( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		_state = _prevState;
-
-		window.addEventListener( 'keydown', keydown, false );
-
-	}
-
-	function mousedown( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		event.preventDefault();
-		event.stopPropagation();
-
-		if ( _state === STATE.NONE ) {
-
-			_state = event.button;
-
-		}
-
-		if ( _state === STATE.ROTATE && !_this.noRotate ) {
-
-			_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
-
-		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {
-
-			_zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
-
-		} else if ( _state === STATE.PAN && !_this.noPan ) {
-
-			_panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
-
-		}
-
-		document.addEventListener( 'mousemove', mousemove, false );
-		document.addEventListener( 'mouseup', mouseup, false );
-
-	}
-
-	function mousemove( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		event.preventDefault();
-		event.stopPropagation();
-
-		if ( _state === STATE.ROTATE && !_this.noRotate ) {
-
-			_rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
-
-		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {
-
-			_zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
-
-		} else if ( _state === STATE.PAN && !_this.noPan ) {
-
-			_panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
-
-		}
-
-	}
-
-	function mouseup( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		event.preventDefault();
-		event.stopPropagation();
-
-		_state = STATE.NONE;
-
-		document.removeEventListener( 'mousemove', mousemove );
-		document.removeEventListener( 'mouseup', mouseup );
-
-	}
-
-	function mousewheel( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		event.preventDefault();
-		event.stopPropagation();
-
-		var delta = 0;
-
-		if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
-
-			delta = event.wheelDelta / 40;
-
-		} else if ( event.detail ) { // Firefox
-
-			delta = - event.detail / 3;
-
-		}
-
-		_zoomStart.y += delta * 0.01;
-
-	}
-
-	function touchstart( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		switch ( event.touches.length ) {
-
-			case 1:
-				_state = STATE.TOUCH_ROTATE;
-				_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-			case 2:
-				_state = STATE.TOUCH_ZOOM;
-				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
-				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
-				_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
-				break;
-
-			case 3:
-				_state = STATE.TOUCH_PAN;
-				_panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-			default:
-				_state = STATE.NONE;
-
-		}
-
-	}
-
-	function touchmove( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		event.preventDefault();
-		event.stopPropagation();
-
-		switch ( event.touches.length ) {
-
-			case 1:
-				_rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-			case 2:
-				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
-				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
-				_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
-				break;
-
-			case 3:
-				_panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-			default:
-				_state = STATE.NONE;
-
-		}
-
-	}
-
-	function touchend( event ) {
-
-		if ( _this.enabled === false ) return;
-
-		switch ( event.touches.length ) {
-
-			case 1:
-				_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-			case 2:
-				_touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
-				break;
-
-			case 3:
-				_panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
-				break;
-
-		}
-
-		_state = STATE.NONE;
-
-	}
-
-	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
-
-	this.domElement.addEventListener( 'mousedown', mousedown, false );
-
-	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
-	this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
-
-	this.domElement.addEventListener( 'touchstart', touchstart, false );
-	this.domElement.addEventListener( 'touchend', touchend, false );
-	this.domElement.addEventListener( 'touchmove', touchmove, false );
-
-	window.addEventListener( 'keydown', keydown, false );
-	window.addEventListener( 'keyup', keyup, false );
-
-	this.handleResize();
-
-};
-
-THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
-
-/**
- * @author bhouston / http://exocortex.com/
- * @author zz85 / http://github.com/zz85
- */
-
-THREE.ColorConverter = {
-
-	setHSV: function ( color, h, s, v ) {
-
-		// https://gist.github.com/xpansive/1337890#file-index-js
-		return color.setHSL( h, ( s * v ) / ( ( h = ( 2 - s ) * v ) < 1 ? h : ( 2 - h ) ), h * 0.5 );
-
-	},
-
-	getHSV: function( color ) {
-
-		var hsl = color.getHSL();
-
-		// based on https://gist.github.com/xpansive/1337890#file-index-js
-		hsl.s *= ( hsl.l < 0.5 ) ? hsl.l : ( 1 - hsl.l );
-
-		return {
-			h: hsl.h,
-			s: 2 * hsl.s / ( hsl.l + hsl.s ),
-			v: hsl.l + hsl.s
-		};
-	},
-
-	// where c, m, y, k is between 0 and 1
-	
-	setCMYK: function ( color, c, m, y, k ) {
-
-		var r = ( 1 - c ) * ( 1 - k );
-		var g = ( 1 - m ) * ( 1 - k );
-		var b = ( 1 - y ) * ( 1 - k );
-
-		return color.setRGB( r, g, b );
-
-	},
-
-	getCMYK: function ( color ) {
-
-		var r = color.r;
-		var g = color.g;
-		var b = color.b;
-		var k = 1 - Math.max(r, g, b);
-		var c = ( 1 - r - k ) / ( 1 - k );
-		var m = ( 1 - g - k ) / ( 1 - k );
-		var y = ( 1 - b - k ) / ( 1 - k );
-
-		return {
-			c: c, m: m, y: y, k: k
-		};
-
-	}
-
-
-};
-
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.SVGRenderer = function () {
-
-	console.log( 'THREE.SVGRenderer', THREE.REVISION );
-
-	var _this = this,
-	_renderData, _elements, _lights,
-	_projector = new THREE.Projector(),
-	_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
-	_svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf,
-
-	_v1, _v2, _v3, _v4,
-
-	_clipBox = new THREE.Box2(),
-	_elemBox = new THREE.Box2(),
-
-	_color = new THREE.Color(),
-	_diffuseColor = new THREE.Color(),
-	_ambientLight = new THREE.Color(),
-	_directionalLights = new THREE.Color(),
-	_pointLights = new THREE.Color(),
-
-	_w, // z-buffer to w-buffer
-	_vector3 = new THREE.Vector3(), // Needed for PointLight
-
-	_svgPathPool = [], _svgCirclePool = [], _svgLinePool = [],
-	_svgNode, _pathCount, _circleCount, _lineCount,
-	_quality = 1;
-
-	this.domElement = _svg;
-
-	this.autoClear = true;
-	this.sortObjects = true;
-	this.sortElements = true;
-
-	this.info = {
-
-		render: {
-
-			vertices: 0,
-			faces: 0
-
-		}
-
-	}
-
-	this.setQuality = function( quality ) {
-
-		switch(quality) {
-
-			case "high": _quality = 1; break;
-			case "low": _quality = 0; break;
-
-		}
-
-	};
-
-	// WebGLRenderer compatibility
-
-	this.supportsVertexTextures = function () {};
-	this.setFaceCulling = function () {};
-
-	this.setClearColor = function ( color, alpha ) {
-
-		// TODO
-
-	};
-
-	this.setSize = function( width, height ) {
-
-		_svgWidth = width; _svgHeight = height;
-		_svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2;
-
-		_svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight );
-		_svg.setAttribute( 'width', _svgWidth );
-		_svg.setAttribute( 'height', _svgHeight );
-
-		_clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf );
-		_clipBox.max.set( _svgWidthHalf, _svgHeightHalf );
-
-	};
-
-	this.clear = function () {
-
-		_pathCount = 0;
-		_circleCount = 0;
-		_lineCount = 0;
-
-		while ( _svg.childNodes.length > 0 ) {
-
-			_svg.removeChild( _svg.childNodes[ 0 ] );
-
-		}
-
-	};
-
-	this.render = function ( scene, camera ) {
-
-		if ( camera instanceof THREE.Camera === false ) {
-
-			console.error( 'THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.' );
-			return;
-
-		}
-
-		if ( this.autoClear === true ) this.clear();
-
-		_this.info.render.vertices = 0;
-		_this.info.render.faces = 0;
-
-		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
-		_elements = _renderData.elements;
-		_lights = _renderData.lights;
-
-		calculateLights( _lights );
-
-		for ( var e = 0, el = _elements.length; e < el; e ++ ) {
-
-			var element = _elements[ e ];
-			var material = element.material;
-
-			if ( material === undefined || material.visible === false ) continue;
-
-			_elemBox.makeEmpty();
-
-			if ( element instanceof THREE.RenderableParticle ) {
-
-				_v1 = element;
-				_v1.x *= _svgWidthHalf; _v1.y *= -_svgHeightHalf;
-
-				renderParticle( _v1, element, material );
-
-			} else if ( element instanceof THREE.RenderableLine ) {
-
-				_v1 = element.v1; _v2 = element.v2;
-
-				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
-				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
-
-				_elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderLine( _v1, _v2, element, material );
-
-				}
-
-			} else if ( element instanceof THREE.RenderableFace3 ) {
-
-				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
-
-				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
-				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
-				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;
-
-				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
-				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
-				_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf;
-
-				_elemBox.setFromPoints( [
-					_v1.positionScreen,
-					_v2.positionScreen,
-					_v3.positionScreen
-				] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderFace3( _v1, _v2, _v3, element, material );
-
-				}
-
-			} else if ( element instanceof THREE.RenderableFace4 ) {
-
-				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3; _v4 = element.v4;
-
-				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
-				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
-				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;
-				if ( _v4.positionScreen.z < -1 || _v4.positionScreen.z > 1 ) continue;
-
-				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= -_svgHeightHalf;
-				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= -_svgHeightHalf;
-				_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= -_svgHeightHalf;
-				_v4.positionScreen.x *= _svgWidthHalf; _v4.positionScreen.y *= -_svgHeightHalf;
-
-				_elemBox.setFromPoints( [
-					_v1.positionScreen,
-					_v2.positionScreen,
-					_v3.positionScreen,
-					_v4.positionScreen
-				] );
-
-				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
-
-					renderFace4( _v1, _v2, _v3, _v4, element, material );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function calculateLights( lights ) {
-
-		_ambientLight.setRGB( 0, 0, 0 );
-		_directionalLights.setRGB( 0, 0, 0 );
-		_pointLights.setRGB( 0, 0, 0 );
-
-		for ( var l = 0, ll = lights.length; l < ll; l++ ) {
-
-			var light = lights[ l ];
-			var lightColor = light.color;
-
-			if ( light instanceof THREE.AmbientLight ) {
-
-				_ambientLight.r += lightColor.r;
-				_ambientLight.g += lightColor.g;
-				_ambientLight.b += lightColor.b;
-
-			} else if ( light instanceof THREE.DirectionalLight ) {
-
-				_directionalLights.r += lightColor.r;
-				_directionalLights.g += lightColor.g;
-				_directionalLights.b += lightColor.b;
-
-			} else if ( light instanceof THREE.PointLight ) {
-
-				_pointLights.r += lightColor.r;
-				_pointLights.g += lightColor.g;
-				_pointLights.b += lightColor.b;
-
-			}
-
-		}
-
-	}
-
-	function calculateLight( lights, position, normal, color ) {
-
-		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
-
-			var light = lights[ l ];
-			var lightColor = light.color;
-
-			if ( light instanceof THREE.DirectionalLight ) {
-
-				var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ).normalize();
-
-				var amount = normal.dot( lightPosition );
-
-				if ( amount <= 0 ) continue;
-
-				amount *= light.intensity;
-
-				color.r += lightColor.r * amount;
-				color.g += lightColor.g * amount;
-				color.b += lightColor.b * amount;
-
-			} else if ( light instanceof THREE.PointLight ) {
-
-				var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld );
-
-				var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
-
-				if ( amount <= 0 ) continue;
-
-				amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
-
-				if ( amount == 0 ) continue;
-
-				amount *= light.intensity;
-
-				color.r += lightColor.r * amount;
-				color.g += lightColor.g * amount;
-				color.b += lightColor.b * amount;
-
-			}
-
-		}
-
-	}
-
-	function renderParticle( v1, element, material ) {
-
-		/*
-		_svgNode = getCircleNode( _circleCount++ );
-		_svgNode.setAttribute( 'cx', v1.x );
-		_svgNode.setAttribute( 'cy', v1.y );
-		_svgNode.setAttribute( 'r', element.scale.x * _svgWidthHalf );
-
-		if ( material instanceof THREE.ParticleCircleMaterial ) {
-
-			_color.r = _ambientLight.r + _directionalLights.r + _pointLights.r;
-			_color.g = _ambientLight.g + _directionalLights.g + _pointLights.g;
-			_color.b = _ambientLight.b + _directionalLights.b + _pointLights.b;
-
-			_color.r = material.color.r * _color.r;
-			_color.g = material.color.g * _color.g;
-			_color.b = material.color.b * _color.b;
-
-			_color.updateStyleString();
-
-			_svgNode.setAttribute( 'style', 'fill: ' + _color.__styleString );
-
-		}
-
-		_svg.appendChild( _svgNode );
-		*/
-
-	}
-
-	function renderLine ( v1, v2, element, material ) {
-
-		_svgNode = getLineNode( _lineCount ++ );
-
-		_svgNode.setAttribute( 'x1', v1.positionScreen.x );
-		_svgNode.setAttribute( 'y1', v1.positionScreen.y );
-		_svgNode.setAttribute( 'x2', v2.positionScreen.x );
-		_svgNode.setAttribute( 'y2', v2.positionScreen.y );
-
-		if ( material instanceof THREE.LineBasicMaterial ) {
-
-			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );
-
-			_svg.appendChild( _svgNode );
-
-		}
-
-	}
-
-	function renderFace3( v1, v2, v3, element, material ) {
-
-		_this.info.render.vertices += 3;
-		_this.info.render.faces ++;
-
-		_svgNode = getPathNode( _pathCount ++ );
-		_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );
-
-		if ( material instanceof THREE.MeshBasicMaterial ) {
-
-			_color.copy( material.color );
-
-			if ( material.vertexColors === THREE.FaceColors ) {
-
-				_color.multiply( element.color );
-
-			}
-
-		} else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
-
-			_diffuseColor.copy( material.color );
-
-			if ( material.vertexColors === THREE.FaceColors ) {
-
-				_diffuseColor.multiply( element.color );
-
-			}
-
-			_color.copy( _ambientLight );
-
-			calculateLight( _lights, element.centroidModel, element.normalModel, _color );
-
-			_color.multiply( _diffuseColor ).add( material.emissive );
-
-		} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-			_w = 1 - ( material.__2near / (material.__farPlusNear - element.z * material.__farMinusNear) );
-			_color.setRGB( _w, _w, _w );
-
-		} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-			var normal = element.normalModelView;
-
-			_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-		}
-
-		if ( material.wireframe ) {
-
-			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );
-
-		} else {
-
-			_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );
-
-		}
-
-		_svg.appendChild( _svgNode );
-
-	}
-
-	function renderFace4( v1, v2, v3, v4, element, material ) {
-
-		_this.info.render.vertices += 4;
-		_this.info.render.faces ++;
-
-		_svgNode = getPathNode( _pathCount ++ );
-		_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + ' L ' + v4.positionScreen.x + ',' + v4.positionScreen.y + 'z' );
-
-		if ( material instanceof THREE.MeshBasicMaterial ) {
-
-			_color.copy( material.color );
-
-			if ( material.vertexColors === THREE.FaceColors ) {
-
-				_color.multiply( element.color );
-
-			}
-
-		} else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
-
-			_diffuseColor.copy( material.color );
-
-			if ( material.vertexColors === THREE.FaceColors ) {
-
-				_diffuseColor.multiply( element.color );
-
-			}
-
-			_color.copy( _ambientLight );
-
-			calculateLight( _lights, element.centroidModel, element.normalModel, _color );
-
-			_color.multiply( _diffuseColor ).add( material.emissive );
-
-		} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-			_w = 1 - ( material.__2near / (material.__farPlusNear - element.z * material.__farMinusNear) );
-			_color.setRGB( _w, _w, _w );
-
-		} else if ( material instanceof THREE.MeshNormalMaterial ) {
-
-			var normal = element.normalModelView;
-
-			_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
-
-		}
-
-		if ( material.wireframe ) {
-
-			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );
-
-		} else {
-
-			_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );
-
-		}
-
-		_svg.appendChild( _svgNode );
-
-	}
-
-	function getLineNode( id ) {
-
-		if ( _svgLinePool[ id ] == null ) {
-
-			_svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );
-
-			if ( _quality == 0 ) {
-
-				_svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
-
-			}
-
-			return _svgLinePool[ id ];
-
-		}
-
-		return _svgLinePool[ id ];
-
-	}
-
-	function getPathNode( id ) {
-
-		if ( _svgPathPool[ id ] == null ) {
-
-			_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
-
-			if ( _quality == 0 ) {
-
-				_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
-
-			}
-
-			return _svgPathPool[ id ];
-
-		}
-
-		return _svgPathPool[ id ];
-
-	}
-
-	function getCircleNode( id ) {
-
-		if ( _svgCirclePool[id] == null ) {
-
-			_svgCirclePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'circle' );
-
-			if ( _quality == 0 ) {
-
-				_svgCirclePool[id].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
-
-			}
-
-			return _svgCirclePool[ id ];
-
-		}
-
-		return _svgCirclePool[ id ];
-
-	}
-
-	function pad( str ) {
-
-		while ( str.length < 6 ) str = '0' + str;
-		return str;
-
-	}
-
-};
diff --git a/emperor/support_files/js/abc-view-controller.js b/emperor/support_files/js/abc-view-controller.js
new file mode 100644
index 0000000..4693dbe
--- /dev/null
+++ b/emperor/support_files/js/abc-view-controller.js
@@ -0,0 +1,187 @@
+define([
+    'jquery',
+    'underscore'
+], function($, _) {
+  /**
+   *
+   * @class EmperorViewControllerABC
+   *
+   * Initializes an abstract tab. This has to be contained in a DOM object and
+   * will use the full size of that container.  The title represents the title
+   * of the jQuery tab.  The description will be used as help text to describe
+   * the functionality of each subclass tab.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {String} title Title of the tab.
+   * @param {String} description Helper description.
+   *
+   * @return {EmperorViewControllerABC} Returns an instance of the
+   * EmperorViewControllerABC.
+   * @constructs EmperorViewControllerABC
+   *
+   */
+  function EmperorViewControllerABC(container, title, description) {
+    /**
+     * @type {Node}
+     * jQuery element for the parent container.
+     */
+    this.$container = $(container);
+    /**
+     * @type {String}
+     * Human-readable title of the tab.
+     */
+    this.title = title;
+    /**
+     * @type {String}
+     * Human-readable description of the tab.
+     */
+    this.description = description;
+
+    /**
+     * @type {Node}
+     * jQuery element for the canvas, which contains the header and the body.
+     */
+    this.$canvas = null;
+    /**
+     * @type {Node}
+     * jQuery element for the body, which contains the lowermost elements
+     * displayed in tab. This goes below the header.
+     */
+    this.$body = null;
+    /**
+     * @type {Node}
+     * jQuery element for the header which contains the uppermost elements
+     * displayed in a tab.
+     */
+    this.$header = null;
+    /**
+     * @type {Boolean}
+     * Indicates whether the tab is front most
+     * @default false
+     */
+    this.active = false;
+    /**
+     * @type {String}
+     * Unique hash identifier for the tab instance.
+     * @default "EMPtab-xxxxxxx"
+     */
+    this.identifier = 'EMPtab-' + Math.round(1000000 * Math.random());
+    /**
+     * @type {Boolean}
+     * Indicates if tab can be accessed.
+     * @default true
+     */
+    this.enabled = true;
+
+    if (this.$container.length < 1) {
+      throw new Error('Emperor requires a valid container, ' +
+          this.$container + ' does not exist in the DOM.');
+    }
+
+    // the canvas contains both the header and the body, note that for all
+    // these divs the width should be 100% (whatever we have available), but
+    // the height is much trickier, see the resize method for more information
+    this.$canvas = $('<div name="emperor-view-controller-canvas"></div>');
+    this.$canvas.width('100%');
+    this.$container.append(this.$canvas);
+
+    this.$canvas.width(this.$container.width());
+    this.$canvas.height(this.$container.height());
+
+    // the margin and width properties are set this way to center all the
+    // contents of the divs themselves, see this SO answer:
+    // http://stackoverflow.com/a/114549
+    this.$header = $('<div name="emperor-view-controller-header"></div>');
+    this.$header.css('margin', '0 auto');
+    this.$header.css('width', '100%');
+
+    this.$body = $('<div name="emperor-view-controller-body"></div>');
+    this.$body.css('margin', '0 auto');
+    this.$body.css('width', '100%');
+
+    // inherit the size of the container minus the space being used for the
+    // header
+    this.$body.height(this.$canvas.height() - this.$header.height());
+    this.$body.width(this.$canvas.width());
+
+    this.$canvas.append(this.$header);
+    this.$canvas.append(this.$body);
+
+    return this;
+  }
+
+  /**
+   * Sets whether or not the tab can be modified or accessed.
+   *
+   * @param {Boolean} trulse option to enable tab.
+   */
+  EmperorViewControllerABC.prototype.setEnabled = function(trulse) {
+    if (typeof(trulse) === 'boolean') {
+      this.enabled = trulse;
+    }
+    else {
+      throw new Error('`trulse` can only be of boolean type');
+    }
+  };
+
+  /**
+   * Sets whether or not the tab is visible.
+   *
+   * @param {Boolean} trulse option to activate tab
+   * (i.e. move tab to foreground).
+   */
+  EmperorViewControllerABC.prototype.setActive = function(trulse) {
+    if (this.enabled === true) {
+      if (typeof(trulse) === 'boolean') {
+        this.active = trulse;
+      }
+      else {
+        throw new Error('`trulse` can only be of boolean type');
+      }
+    }
+  };
+
+  /**
+   * Resizes the container, note that the body will take whatever space is
+   * available after considering the size of the header. The header shouldn't
+   * have height variable objects, once added their height shouldn't really
+   * change.
+   *
+   * @param {Float} width the container width.
+   * @param {Float} height the container height.
+   */
+  EmperorViewControllerABC.prototype.resize = function(width, height) {
+    // This padding is required in order to make space
+    // for the horizontal menus
+    var padding = 10;
+    this.$canvas.height(height);
+    this.$canvas.width(width - padding);
+
+    this.$header.width(width - padding);
+
+    // the body has to account for the size used by the header
+    this.$body.width(width - padding);
+    this.$body.height(height - this.$header.height());
+  };
+
+  /**
+   *
+   * Converts the current instance into a JSON string.
+   *
+   * @return {Object} ready to serialize representation of self.
+   */
+  EmperorViewControllerABC.prototype.toJSON = function() {
+    throw Error('Not implemented');
+  };
+
+  /**
+   * Decodes JSON string and modifies its own instance variables accordingly.
+   *
+   * @param {Object} parsed JSON string representation of an instance.
+   */
+  EmperorViewControllerABC.prototype.fromJSON = function(jsonString) {
+    throw Error('Not implemented');
+  };
+
+  return {'EmperorViewControllerABC': EmperorViewControllerABC};
+});
diff --git a/emperor/support_files/js/animate.js b/emperor/support_files/js/animate.js
new file mode 100644
index 0000000..a191aad
--- /dev/null
+++ b/emperor/support_files/js/animate.js
@@ -0,0 +1,276 @@
+define([
+    'underscore',
+    'trajectory'
+],
+function(_, trajectory) {
+  var getSampleNamesAndDataForSortedTrajectories =
+    trajectory.getSampleNamesAndDataForSortedTrajectories;
+  var getMinimumDelta = trajectory.getMinimumDelta;
+  var TrajectoryOfSamples = trajectory.TrajectoryOfSamples;
+
+  /**
+   *
+   * @class AnimationDirector
+   *
+   * This object represents an animation director, as the name implies,
+   * is an object that manages an animation. Takes the for a plot (mapping file
+   * and coordinates) as well as the metadata categories we want to animate
+   * over.  This object gets called in the main emperor module when an
+   * animation starts and an instance will only be alive for one animation
+   * cycle i. e. until the cycle hits the final frame of the animation.
+   *
+   * @param {String[]} mappingFileHeaders an Array of strings containing
+   * metadata mapping file headers.
+   * @param {Object[]} mappingFileData an Array where the indices are sample
+   * identifiers and each of the contained elements is an Array of strings where
+   * the first element corresponds to the first data for the first column in the
+   * mapping file (mappingFileHeaders).
+   * @param {Object[]} coordinatesData an Array of Objects where the indices are
+   * the sample identifiers and each of the objects has the following
+   * properties: x, y, z, name, color, P1, P2, P3, ... PN where N is the number
+   * of dimensions in this dataset.
+   * @param {String} gradientCategory a string with the name of the mapping file
+   * header where the data that spreads the samples over a gradient is
+   * contained, usually time or days_since_epoch. Note that this should be an
+   * all numeric category.
+   * @param {String} trajectoryCategory a string with the name of the mapping
+   * file header where the data that groups the samples is contained, this will
+   * usually be BODY_SITE, HOST_SUBJECT_ID, etc..
+   *
+   * @return {AnimationDirector} returns an animation director if the parameters
+   * passed in were all valid.
+   *
+   * @throws {Error} Note that this class will raise an Error in any of the
+   * following cases:
+   * - One of the input arguments is undefined.
+   * - If gradientCategory is not in the mappingFileHeaders.
+   * - If trajectoryCategory is not in the mappingFileHeaders.
+   * @constructs AnimationDirector
+   */
+  function AnimationDirector(mappingFileHeaders, mappingFileData,
+                             coordinatesData, gradientCategory,
+                             trajectoryCategory) {
+
+    // all arguments are required
+    if (mappingFileHeaders === undefined || mappingFileData === undefined ||
+      coordinatesData === undefined || gradientCategory === undefined ||
+      trajectoryCategory === undefined) {
+      throw new Error('All arguments are required');
+    }
+
+    var index;
+
+    index = mappingFileHeaders.indexOf(gradientCategory);
+    if (index == -1) {
+      throw new Error('Could not find the gradient category in the mapping' +
+                      ' file');
+    }
+    index = mappingFileHeaders.indexOf(trajectoryCategory);
+    if (index == -1) {
+      throw new Error('Could not find the trajectory category in the mapping' +
+                      ' file');
+    }
+
+    /**
+     * @type {String[]}
+     mappingFileHeaders an Array of strings containing metadata mapping file
+     headers.
+     */
+    this.mappingFileHeaders = mappingFileHeaders;
+    /**
+     * @type {Object[]}
+     *an Array where the indices are sample identifiers
+     * and each of the contained elements is an Array of strings where the first
+     * element corresponds to the first data for the first column in the mapping
+     * file (mappingFileHeaders).
+     */
+    this.mappingFileData = mappingFileData;
+    /**
+     * @type {Object[]}
+     * an Array of Objects where the indices are the
+     * sample identifiers and each of the objects has the following properties:
+     * x, y, z, name, color, P1, P2, P3, ... PN where N is the number of
+     * dimensions in this dataset.
+     */
+    this.coordinatesData = coordinatesData;
+    /**
+     * @type {String}
+     *a string with the name of the mapping file
+     * header where the data that spreads the samples over a gradient is
+     * contained, usually time or days_since_epoch. Note that this should be an
+     * all numeric category
+     */
+    this.gradientCategory = gradientCategory;
+    /**
+     * @type {String}
+     * a string with the name of the mapping file
+     * header where the data that groups the samples is contained, this will
+     * usually be BODY_SITE, HOST_SUBJECT_ID, etc..
+     */
+    this.trajectoryCategory = trajectoryCategory;
+
+    /**
+     * @type {Float}
+     * A floating point value determining what the minimum separation between
+     * samples along the gradients is. Will be null until it is initialized to
+     * the values according to the input data.
+     * @default null
+     */
+    this.minimumDelta = null;
+    /**
+     * @type {Integer}
+     * Maximum length the groups of samples have along a gradient.
+     * @default null
+     */
+    this.maximumTrajectoryLength = null;
+    /*
+     * @type {Integer}
+     * The current frame being served by the director
+     * @default -1
+     */
+    this.currentFrame = -1;
+    /**
+     * @type {Array}
+     * Array where each element in the trajectory is a trajectory with the
+     * interpolated points in it.
+     */
+    this.trajectories = new Array();
+
+    this.initializeTrajectories();
+    this.getMaximumTrajectoryLength();
+
+    return this;
+  }
+
+  /**
+   *
+   * Initializes the trajectories that the director manages.
+   *
+   */
+  AnimationDirector.prototype.initializeTrajectories = function() {
+
+    var chewedData = null, trajectoryBuffer = null, minimumDelta;
+    var sampleNamesBuffer = new Array(), gradientPointsBuffer = new Array();
+    var coordinatesBuffer = new Array();
+    var chewedDataBuffer = null;
+
+    // compute a dictionary from where we will extract the germane data
+    chewedData = getSampleNamesAndDataForSortedTrajectories(
+        this.mappingFileHeaders, this.mappingFileData, this.coordinatesData,
+        this.trajectoryCategory, this.gradientCategory);
+
+    if (chewedData === null) {
+      throw new Error('Error initializing the trajectories, could not ' +
+                      'compute the data');
+    }
+
+    // calculate the minimum delta per step
+    this.minimumDelta = getMinimumDelta(chewedData);
+
+    // we have to iterate over the keys because chewedData is a dictionary-like
+    // object, if possible this should be changed in the future to be an Array
+    for (var key in chewedData) {
+
+      // re-initalize the arrays, essentially dropping all the previously
+      // existing information
+      sampleNamesBuffer = [];
+      gradientPointsBuffer = [];
+      coordinatesBuffer = [];
+
+      // buffer this to avoid the multiple look-ups below
+      chewedDataBuffer = chewedData[key];
+
+      // each of the keys is a trajectory name i. e. CONTROL, TREATMENT, etc
+      // we are going to generate buffers so we can initialize the trajectory
+      for (var index = 0; index < chewedDataBuffer.length; index++) {
+        // list of sample identifiers
+        sampleNamesBuffer.push(chewedDataBuffer[index]['name']);
+
+        // list of the value each sample has in the gradient
+        gradientPointsBuffer.push(chewedDataBuffer[index]['value']);
+
+        // x, y and z values for the coordinates data
+        coordinatesBuffer.push({'x': chewedDataBuffer[index]['x'],
+                                'y': chewedDataBuffer[index]['y'],
+                                'z': chewedDataBuffer[index]['z']});
+      }
+
+      // Don't add a trajectory unless it has more than one sample in the
+      // gradient. For example, there's no reason why we should animate a
+      // trajectory that has 3 samples at timepoint 0 ([0, 0, 0]) or a
+      // trajectory that has just one sample at timepoint 0 ([0])
+      if (sampleNamesBuffer.length <= 1 ||
+          _.uniq(gradientPointsBuffer).length <= 1) {
+        continue;
+      }
+
+      // create the trajectory object
+      trajectoryBuffer = new TrajectoryOfSamples(sampleNamesBuffer, key,
+          gradientPointsBuffer, coordinatesBuffer, this.minimumDelta);
+
+      this.trajectories.push(trajectoryBuffer);
+
+    }
+    return;
+  };
+
+  /**
+   *
+   * Retrieves the lengths of all the trajectories and figures out which of
+   * them is the longest one, then assigns that value to the
+   * maximumTrajectoryLength property.
+   * @return {Integer} Maximum trajectory length
+   *
+   */
+  AnimationDirector.prototype.getMaximumTrajectoryLength = function() {
+    if (this.maximumTrajectoryLength === null) {
+      this._computeN();
+    }
+
+    return this.maximumTrajectoryLength;
+  };
+
+  /**
+   *
+   * Helper function to compute the maximum length of the trajectories that the
+   * director is in charge of.
+   * @private
+   *
+   */
+  AnimationDirector.prototype._computeN = function() {
+    var arrayOfLengths = new Array();
+
+    // retrieve the length of all the trajectories
+    for (var index = 0; index < this.trajectories.length; index++) {
+      arrayOfLengths.push(
+          this.trajectories[index].interpolatedCoordinates.length);
+    }
+
+    // assign the value of the maximum value for these lengths
+    this.maximumTrajectoryLength = _.max(arrayOfLengths);
+  };
+
+  /**
+   *
+   * Helper method to update the value of the currentFrame property.
+   *
+   */
+  AnimationDirector.prototype.updateFrame = function() {
+    if (this.animationCycleFinished() === false) {
+      this.currentFrame = this.currentFrame + 1;
+    }
+  };
+
+  /**
+   *
+   * Check whether or not the animation cycle has finished for this object.
+   * @return {bool} True if the animation has reached it's end and False if the
+   * animation still has frames to go.
+   *
+   */
+  AnimationDirector.prototype.animationCycleFinished = function() {
+    return this.currentFrame > this.getMaximumTrajectoryLength();
+  };
+
+  return AnimationDirector;
+});
diff --git a/emperor/support_files/js/axes-controller.js b/emperor/support_files/js/axes-controller.js
new file mode 100644
index 0000000..c1156fb
--- /dev/null
+++ b/emperor/support_files/js/axes-controller.js
@@ -0,0 +1,441 @@
+define([
+    'jquery',
+    'underscore',
+    'view',
+    'viewcontroller',
+    'd3',
+    'contextmenu'
+], function($, _, DecompositionView, ViewControllers, d3, contextmenu) {
+  var EmperorViewController = ViewControllers.EmperorViewController;
+
+  /**
+   * @class AxesController
+   *
+   * Controls the axes that are displayed on screen as well as their
+   * orientation.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {Object} decompViewDict This is object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {AxesController}
+   * @constructs AxesController
+   * @extends EmperorViewControllerABC
+   */
+  function AxesController(container, decompViewDict) {
+    var helpmenu = 'Change the visible dimensions of the data';
+    var title = 'Axes';
+    var scope = this;
+    EmperorViewController.call(this, container, title, helpmenu,
+                               decompViewDict);
+
+    var colors = '<table style="width:inherit; border:none;">';
+    colors += '<tr><td>Axes and Labels Color</td>';
+    colors += '<td><input type="text" name="axes-color"/></td></tr>';
+    colors += '<tr><td>Background Color</td>';
+    colors += '<td><input type="text" name="background-color"/></td>';
+    colors += '</table>';
+    this.$body.append(colors);
+
+    // the jupyter notebook add style on the tables, so remove it
+    this.$body.find('tr').css('border', 'none');
+    this.$body.find('td').css('border', 'none');
+
+    var opts = {color: 'white',
+                preferredFormat: 'name',
+                palette: [['black', 'white']],
+                showPalette: true,
+                showInput: true,
+                allowEmpty: false,
+                showInitial: true,
+                clickoutFiresChange: true,
+                change: function(color) {
+                  // We let the controller deal with the callback, the only
+                  // things we need are the name of the element triggerring
+                  // the color change and the color as an integer (note that
+                  // we are parsing from a string hence we have to indicate
+                  // the numerical base)
+                  scope.colorChanged($(this).attr('name'),
+                                     parseInt(color.toHex(), 16));
+                }
+    };
+    // spectrumify all the elements in the body that have a name ending in
+    // color
+    this.$body.find('[name="axes-color"]').spectrum(opts);
+    opts.color = 'black';
+    this.$body.find('[name="background-color"]').spectrum(opts);
+
+    /**
+     * @type {Node}
+     * jQuery object containing the scree plot.
+     *
+     * The style set here is important, allows for automatic resizing.
+     *
+     * @private
+     */
+    this.$_screePlotContainer = $('<div name="scree-plot">');
+    this.$_screePlotContainer.css({'display': 'inline-block',
+                                   'position': 'relative',
+                                   'width': '100%',
+                                   'padding-bottom': '100%',
+                                   'vertical-align': 'middle',
+                                   'overflow': 'hidden'});
+
+    this.$body.append(this.$_screePlotContainer);
+
+    /**
+     * @type {Node}
+     * The SVG node where the scree plot lives. For use with D3.
+     */
+    this.svg = null;
+
+    /**
+     * @type {Node}
+     * The display table where information about currently visible axes is
+     * shown.
+     */
+    this.$table = null;
+
+    /**
+     * @type {Bool[]}
+     * Which axes are 'flipped', by default all are set to false.
+     * @private
+     */
+    this._flippedAxes = [0, 0, 0];
+
+    // initialize interface elements here
+    $(this).ready(function() {
+      scope.buildDisplayTable();
+      scope._buildScreePlot();
+    });
+
+    return this;
+  }
+  AxesController.prototype = Object.create(EmperorViewController.prototype);
+  AxesController.prototype.constructor = EmperorViewController;
+
+  /**
+   * Create a table to display the visible axis information.
+   *
+   * Note that when this method is executed the table is destroyed, if it
+   * exists, and recreated with the appropriate information.
+   *
+   */
+  AxesController.prototype.buildDisplayTable = function() {
+    if (this.$table !== null) {
+      this.$table.remove();
+    }
+
+    var view = this.decompViewDict[this.activeViewKey], scope = this;
+    var percents = view.decomp.percExpl;
+    var names = ['First', 'Second', 'Third'];
+
+    var table = '<table style="border:none;">';
+    table += '<col align="left"><col align="right"><col align="center">';
+    _.each(view.visibleDimensions, function(dimension, index) {
+      table += '<tr>';
+
+      // axis name
+      table += '<td>' + names[index] + ' Axis' + '</td>';
+
+      // percentage of variation and name
+      table += '<td>PC ' + (dimension + 1) + ' - ' +
+               percents[dimension].toFixed(2) + '%</td>';
+
+      // whether or not the axis is flipped
+      table += '<td>Is' + (scope._flippedAxes[index] ? '' : ' Not') +
+               ' Flipped</td>';
+
+      table += '</tr>';
+
+    });
+    table += '</table>';
+
+    this.$table = $(table);
+    this.$table.css({'width': 'inherit',
+                     'padding-bottom': '10%'
+    });
+
+    this.$header.append(this.$table);
+
+    // the jupyter notebook add style on the tables, so remove it
+    this.$header.find('tr').css('border', 'none');
+    this.$header.find('td').css('border', 'none');
+  };
+
+  /**
+   * Method to build the scree plot and updates the interface appropriately.
+   *
+   * @private
+   *
+   */
+  AxesController.prototype._buildScreePlot = function() {
+    var scope = this;
+    var percents = this.decompViewDict[this.activeViewKey].decomp.percExpl;
+    percents = _.map(percents, function(val, index) {
+      // +1 to account for zero-indexing
+      return {'axis': 'PC ' + (index + 1), 'percent': val,
+              'dimension-index': index};
+    });
+
+    // this chart is based on the example hosted in
+    // https://bl.ocks.org/mbostock/3885304
+    var margin = {top: 10, right: 10, bottom: 30, left: 40},
+        width = this.$body.width() - margin.left - margin.right,
+        height = (this.$body.height() * 0.40) - margin.top - margin.bottom;
+
+    var x = d3.scale.ordinal()
+      .rangeRoundBands([0, width], 0.1);
+
+    var y = d3.scale.linear()
+      .range([height, 0]);
+
+    var xAxis = d3.svg.axis()
+      .scale(x)
+      .orient('bottom');
+
+    var yAxis = d3.svg.axis()
+      .scale(y)
+      .orient('left')
+      .ticks(4);
+
+    // the container of the scree plot
+    var svg = d3.select(this.$_screePlotContainer.get(0)).append('svg')
+      .attr('preserveAspectRatio', 'xMinYMin meet')
+      .attr('viewBox', (-margin.left) + ' ' +
+                       (-margin.top) + ' ' +
+                       (width + margin.left + margin.right) + ' ' +
+                       (height + margin.top + margin.bottom))
+      .style('display', 'inline-block')
+      .style('position', 'absolute')
+      .style('left', '0')
+      .style('top', '0')
+      .append('g');
+
+    this.$_screePlotContainer.height(height + margin.top + margin.bottom);
+
+    // creation of the chart itself
+    x.domain(percents.map(function(d) { return d.axis; }));
+    y.domain([0, d3.max(percents, function(d) { return d.percent; })]);
+
+    // create the x axis
+    svg.append('g')
+      .attr('font', '10px sans-serif')
+      .attr('transform', 'translate(0,' + height + ')')
+      .call(xAxis);
+
+    // create the y axis
+    svg.append('g')
+      .attr('font', '10px sans-serif')
+      .call(yAxis)
+      .append('text')
+      .attr('transform', 'translate(' + (margin.left * (-0.8)) +
+                         ',' + height / 2 + ') rotate(-90)')
+      .style('text-anchor', 'middle')
+      .text('% Variation Explained');
+
+    // draw the bars in the chart
+    svg.selectAll('.bar')
+      .data(percents)
+      .enter().append('rect')
+      .attr('dimension-index', function(d) { return d['dimension-index']; })
+      .attr('fill', 'steelblue')
+      .attr('x', function(d) { return x(d.axis); })
+      .attr('width', x.rangeBand())
+      .attr('y', function(d) { return y(d.percent); })
+      .attr('height', function(d) { return height - y(d.percent); })
+      .on('mouseover', function(d) {
+        $(this).css('fill', 'teal');
+      })
+      .on('mouseout', function(d) {
+        $(this).css('fill', 'steelblue');
+      });
+
+    // figure title
+    svg.append('text')
+      .attr('x', (width / 2))
+      .attr('y', 0)
+      .attr('text-anchor', 'middle')
+      .text('Scree Plot');
+
+    // set the style for the axes lines and ticks
+    svg.selectAll('axis,path,line')
+      .style('fill', 'none')
+      .style('stroke', 'black')
+      .style('stroke-width', '2')
+      .style('shape-rendering', 'crispEdges');
+
+    this.screePlot = svg;
+
+    // This function creates a function callbacks
+    //
+    // The rationale to create this function, was to deal with the fact that
+    // three of the 'context menu' options had the same behaviour, otherwise
+    // we would have had to repeat the code in the returned function.
+    //
+    var callbackFactory = function(callBackIndex) {
+      return (function(key, opts) {
+        var index = parseInt($(this).attr('dimension-index'));
+        scope.updateVisibleAxes(index, callBackIndex);
+      });
+    };
+
+    /*
+      Once we have created the plot, we bind each of the bars to a context
+      menu, hence the selector searches for all the 'rect' tags inside the
+      controller's div.
+
+      The functionality itself is rather simple, each of the options in the
+      context menu allows the user to select the clicked bar as the first,
+      second or third visible axis. With each of these changes, we re-build the
+      display table to reflect the currently visible data (see
+      callbackFactory).
+
+      Finally, there is one option that allows users to reorient the
+      coordinates for that axis.
+     */
+    $.contextMenu({
+      selector: '#' + this.identifier + ' rect',
+      trigger: 'left',
+      items: {
+        'first-axis': {
+          name: 'Set as first axis',
+          callback: callbackFactory(0)
+        },
+        'second-axis': {
+          name: 'Set as second axis',
+          callback: callbackFactory(1)
+        },
+        'third-axis': {
+          name: 'Set as third axis',
+          callback: callbackFactory(2)
+        },
+        'sep1': '---------',
+        'flip-axis': {
+          icon: 'exchange',
+          name: 'Flip axis orientation',
+          callback: function(key, opts) {
+            var index = parseInt($(this).attr('dimension-index'));
+            scope.flipAxis(index);
+          }
+        }
+      }
+    });
+  };
+
+  /**
+   * Callback to reposition an axis into a new position.
+   *
+   * @param {Integer} index The index of the dimension to set as a new visible
+   * axis, in the corresponding position indicated by `position`.
+   * @param {Integer} position The position where the new axis will be set.
+   */
+  AxesController.prototype.updateVisibleAxes = function(index, position) {
+    // update all the visible dimensions
+    _.each(this.decompViewDict, function(decView, key) {
+      // clone to avoid indirectly modifying by reference
+      var visibleDimensions = _.clone(decView.visibleDimensions);
+
+      visibleDimensions[position] = index;
+      decView.changeVisibleDimensions(visibleDimensions);
+    });
+
+    this._flippedAxes[position] = 0;
+
+    this.buildDisplayTable();
+  };
+
+  /**
+   * Callback to change the orientation of an axis
+   *
+   * @param {Integer} index The index of the dimension to re-orient, note that
+   * if this index is not visible, this callback will take no effect.
+   */
+  AxesController.prototype.flipAxis = function(index) {
+    var axIndex;
+
+    // update all the visible dimensions
+    _.each(this.decompViewDict, function(decView, key) {
+
+      axIndex = decView.visibleDimensions.indexOf(index);
+
+      if (axIndex !== -1) {
+        decView.flipVisibleDimension(index);
+      }
+    });
+
+    this._flippedAxes[axIndex] = 1 ^ this._flippedAxes[axIndex];
+    this.buildDisplayTable();
+  };
+
+  /**
+   * Callback to change color of the axes or the background
+   *
+   * @param {String} name The name of the element to change, it can be either
+   * 'axes-color' or 'background-color'.
+   * @param {Integer} color The color to set to the `name`. Should be in an
+   * RGB-like format.
+   */
+  AxesController.prototype.colorChanged = function(name, color) {
+    // for both cases update all the decomposition views and then set the
+    // appropriate colors
+    if (name === 'axes-color') {
+      _.each(this.decompViewDict, function(decView) {
+        decView.axesColor = color;
+        decView.needsUpdate = true;
+      });
+    }
+    else if (name === 'background-color') {
+      _.each(this.decompViewDict, function(decView) {
+        decView.backgroundColor = color;
+        decView.needsUpdate = true;
+      });
+    }
+    else {
+      throw Error('Could not find "' + name + '" only two allowed inputs are' +
+                  '"axes-color" and "background-color"');
+    }
+  };
+
+  /**
+   * Converts the current instance into a JSON string.
+   *
+   * @return {Object} JSON ready representation of self.
+   */
+  AxesController.prototype.toJSON = function() {
+    var json = {};
+
+    var decView = this.decompViewDict[this.activeViewKey];
+
+    json.visibleDimensions = decView.visibleDimensions;
+    json.flippedAxes = this._flippedAxes;
+    json.backgroundColor = decView.backgroundColor;
+    json.axesColor = decView.axesColor;
+
+    return json;
+  };
+
+  /**
+   * Decodes JSON string and modifies its own instance variables accordingly.
+   *
+   * @param {Object} Parsed JSON string representation of self.
+   */
+  AxesController.prototype.fromJSON = function(json) {
+    var decView = this.decompViewDict[this.activeViewKey], scope = this;
+
+    decView.changeVisibleDimensions(json.visibleDimensions);
+
+    _.each(json.flippedAxes, function(element, index) {
+      if (element) {
+        scope.flipAxis(decView.visibleDimensions[index]);
+      }
+    });
+
+    this.colorChanged('axes-color', json.axesColor);
+    this.colorChanged('background-color', json.backgroundColor);
+  };
+
+  return AxesController;
+});
diff --git a/emperor/support_files/js/color-editor.js b/emperor/support_files/js/color-editor.js
new file mode 100644
index 0000000..a2c8483
--- /dev/null
+++ b/emperor/support_files/js/color-editor.js
@@ -0,0 +1,141 @@
+/**
+ * SlickGrid color editor and formatter.
+ *
+ * @module SlickGridColors
+ */
+define([
+    'jquery',
+    'underscore',
+    'view',
+    'viewcontroller',
+    'spectrum'
+],
+function($, _, DecompositionView, ViewControllers, spectrum) {
+
+  /**
+   *
+   * @class ColorEditor
+   *
+   * This class represents a color editor defined by the SlickGrid
+   * project.
+   *
+   * Note, this object is heavily based on classes in slick.editors.js and in
+   * the documentation that can be found [here](https://github.com/mleibman/
+   * SlickGrid/wiki/Writing-custom-cell-editors).
+   *
+   * Also see ColorFormatter, a function in charge of formatting colors for the
+   * SlickGrid object.
+   *
+   * @param {object} args Arguments passed by SlickGrid.
+   *
+   * @constructs ColorEditor
+   * @alias module:SlickGridColors.ColorEditor
+   *
+   */
+  function ColorEditor(args) {
+    var $input;
+    var defaultValue;
+    var scope = this;
+
+    this.init = function() {
+      // make the background look exactly the same when the color is being
+      // edited
+      $(args.container).css('background-color', '#eeeeee');
+
+      $input = $("<div class='colorbox'></div>");
+      $input.css('background-color', args.item.value);
+      $input.appendTo(args.container);
+      $input.spectrum({
+        color: args.item.color,
+        showInput: true,
+        allowEmpty: false,
+        showPalette: false,
+        showInitial: true,
+        clickoutFiresChange: true,
+        className: 'full-spectrum',
+        preferredFormat: 'hex6',
+
+        /* On change callback */
+        change: function(color) {
+          $input.css('background-color', color.toHexString());
+
+          // commit the changes as soon as a new color is selected
+          // http://stackoverflow.com/a/15513516/379593
+          Slick.GlobalEditorLock.commitCurrentEdit();
+        }
+      });
+    };
+
+    this.destroy = function() {
+      $input.spectrum('hide');
+      $input.spectrum('destroy');
+      $input.remove();
+    };
+
+    this.focus = function() {
+      $input.spectrum('show');
+    };
+
+    this.isValueChanged = function() {
+      return $input.spectrum('get').toHexString() !== defaultValue;
+    };
+
+    this.serializeValue = function() {
+      return $input.spectrum('get').toHexString();
+    };
+
+    this.loadValue = function(item) {
+      defaultValue = item[args.column.field];
+      $input.spectrum('set', defaultValue);
+    };
+
+    this.applyValue = function(item, state) {
+      item[args.column.field] = state;
+    };
+
+    this.validate = function() {
+      return {valid: true, msg: null};
+    };
+
+    this.hide = function() {
+      $input.spectrum('hide');
+    };
+
+    this.show = function() {
+      $input.spectrum('show');
+    };
+
+    this.position = function(cellBox) {
+      $input.spectrum('reflow');
+    };
+
+    this.init();
+  }
+
+
+  /**
+   *
+   * Function to format colors for the SlickGrid object.
+   *
+   * This formatter is heavily based in the examples found in
+   * slick.formattters.js and is only intended to be used with ColorFormatter.
+   *
+   * @param {integer} row SlickGrid row.
+   * @param {integer} cell SlickGrid cell.
+   * @param {integer|string|bool} value The value in the row.
+   * @param {object} columnDef SlickGrid column definition.
+   * @param {object} dataContext Data model of the SlickGrid object.
+   *
+   * @return {string} String with a div where the background color is set as
+   * the value that's passed in.
+   *
+   * @alias module:SlickGridColors.ColorFormatter
+   *
+   */
+  function ColorFormatter(row, cell, value, columnDef, dataContext) {
+    return "<div class='colorbox' style='background-color:" + value +
+           ";'></div>";
+  }
+
+  return {'ColorEditor': ColorEditor, 'ColorFormatter': ColorFormatter};
+});
diff --git a/emperor/support_files/js/color-view-controller.js b/emperor/support_files/js/color-view-controller.js
new file mode 100644
index 0000000..2e0d315
--- /dev/null
+++ b/emperor/support_files/js/color-view-controller.js
@@ -0,0 +1,537 @@
+define([
+    'jquery',
+    'underscore',
+    'util',
+    'view',
+    'viewcontroller',
+    'color-editor',
+    'chroma'
+], function($, _, util, DecompositionView, ViewControllers, Color, chroma) {
+
+  // we only use the base attribute class, no need to get the base class
+  var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
+  var ColorEditor = Color.ColorEditor, ColorFormatter = Color.ColorFormatter;
+
+  /**
+   * @class ColorViewController
+   *
+   * Controls the color changing tab in Emperor. Takes care of changes to
+   * color based on metadata, as well as making colorbars if coloring by a
+   * numeric metadata category.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {Object} decompViewDict This is object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {ColorViewController}
+   * @constructs ColorViewController
+   * @extends EmperorAttributeABC
+   */
+  function ColorViewController(container, decompViewDict) {
+    var helpmenu = 'Change the colors of the attributes on the plot, such as ' +
+      'spheres, vectors and ellipsoids.';
+    var title = 'Color';
+
+    // Constant for width in slick-grid
+    var SLICK_WIDTH = 25, scope = this;
+    var name, value, colorItem;
+
+    // Create scale div and checkbox for whether using scalar data or not
+    /**
+     * @type {Node}
+     *  jQuery object holding the colorbar div
+     */
+    this.$scaleDiv = $('<div>');
+    /**
+     * @type {Node}
+     *  jQuery object holding the SVG colorbar
+     */
+    this.$colorScale = $("<svg width='90%' height='100%' " +
+                         "'style='display:block;margin:auto;'></svg>");
+    this.$scaleDiv.append(this.$colorScale);
+    /**
+     * @type {Node}
+     *  jQuery object holding the continuous value checkbox
+     */
+    this.$scaled = $("<input type='checkbox'>");
+    /**
+     * @type {Node}
+     *  jQuery object holding the continuous value label
+     */
+    this.$scaledLabel = $("<label for='scaled'>Continuous values</label>");
+
+    // this class uses a colormap selector, so populate it before calling super
+    // because otherwise the categorySelectionCallback will be called before the
+    // data is populated
+    /**
+     * @type {Node}
+     *  jQuery object holding the select box for the colormaps
+     */
+    this.$colormapSelect = $("<select class='emperor-tab-drop-down'>");
+    var currType = ColorViewController.Colormaps[0].type;
+    var selectOpts = $('<optgroup>').attr('label', currType);
+
+    for (var i = 0; i < ColorViewController.Colormaps.length; i++) {
+      var colormap = ColorViewController.Colormaps[i];
+      // Check if we are in a new optgroup
+      if (colormap.type !== currType) {
+        currType = colormap.type;
+        scope.$colormapSelect.append(selectOpts);
+        selectOpts = $('<optgroup>').attr('label', currType);
+      }
+      var colorItem = $('<option>')
+        .attr('value', colormap.id)
+        .attr('data-type', currType)
+        .text(colormap.name);
+      selectOpts.append(colorItem);
+    }
+    scope.$colormapSelect.append(selectOpts);
+
+    // Build the options dictionary
+    var options = {
+      'valueUpdatedCallback':
+        function(e, args) {
+          var val = args.item.category, color = args.item.value;
+          var group = args.item.plottables;
+          var element = scope.decompViewDict[scope.getActiveDecompViewKey()];
+          scope.setPlottableAttributes(element, color, group);
+        },
+      'categorySelectionCallback':
+        function(evt, params) {
+          // we re-use this same callback regardless of whether the
+          // color or the metadata category changed, maybe we can do
+          // something better about this
+          var category = scope.$select.val();
+          var discrete = $('option:selected', scope.$colormapSelect)
+                           .attr('data-type') == DISCRETE;
+          var colorScheme = scope.$colormapSelect.val();
+
+          var k = scope.getActiveDecompViewKey();
+          var decompViewDict = scope.decompViewDict[k];
+
+          if (discrete) {
+            scope.$scaled.prop('checked', false);
+            scope.$scaled.prop('hidden', true);
+            scope.$scaledLabel.prop('hidden', true);
+          } else {
+            scope.$scaled.prop('hidden', false);
+            scope.$scaledLabel.prop('hidden', false);
+          }
+          var scaled = scope.$scaled.is(':checked');
+          // getting all unique values per categories
+          var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
+            category);
+          // getting color for each uniqueVals
+          var colorInfo = ColorViewController.getColorList(
+            uniqueVals, colorScheme, discrete, scaled);
+          var attributes = colorInfo[0];
+          // fetch the slickgrid-formatted data
+          var data = decompViewDict.setCategory(
+            attributes, scope.setPlottableAttributes, category);
+
+          if (scaled) {
+            plottables = ColorViewController._nonNumericPlottables(
+              uniqueVals, data);
+            // Set SlickGrid for color of non-numeric values and show color bar
+            // for rest if there are non numeric categories
+            if (plottables.length > 0) {
+              scope.setSlickGridDataset(
+                [{category: 'Non-numeric values', value: '#64655d',
+                  plottables: plottables}]);
+            }
+            else {
+              scope.setSlickGridDataset([]);
+            }
+            scope.$scaleDiv.show();
+            scope.$colorScale.html(colorInfo[1]);
+          }
+          else {
+            scope.setSlickGridDataset(data);
+            scope.$scaleDiv.hide();
+          }
+          // Call resize to update all methods for new shows/hides/resizes
+          scope.resize();
+        },
+      'slickGridColumn': {
+        id: 'title', name: '', field: 'value',
+        sortable: false, maxWidth: SLICK_WIDTH,
+        minWidth: SLICK_WIDTH,
+        autoEdit: true,
+        editor: ColorEditor,
+        formatter: ColorFormatter
+      }
+    };
+
+    EmperorAttributeABC.call(this, container, title, helpmenu,
+                             decompViewDict, options);
+    this.$header.append(this.$colormapSelect);
+    this.$header.append(this.$scaled);
+    this.$header.append(this.$scaledLabel);
+    this.$body.prepend(this.$scaleDiv);
+
+    // the chosen select can only be set when the document is ready
+    $(function() {
+      scope.$colormapSelect.chosen({width: '100%', search_contains: true});
+      scope.$colormapSelect.chosen().change(options.categorySelectionCallback);
+      scope.$scaled.on('change', options.categorySelectionCallback);
+    });
+
+    return this;
+  }
+  ColorViewController.prototype = Object.create(EmperorAttributeABC.prototype);
+  ColorViewController.prototype.constructor = EmperorAttributeABC;
+
+
+  /**
+   * Helper for building the plottables for non-numeric data
+   *
+   * @param {String[]} uniqueVals Array of unique values for the category
+   * @param {Object} data SlickGrid formatted data from setCategory function
+   *
+   * @return {Plottable[]} Array of plottables for all non-numeric values
+   * @private
+   *
+   */
+   ColorViewController._nonNumericPlottables = function(uniqueVals, data) {
+     // Filter down to only non-numeric data
+     var split = util.splitNumericValues(uniqueVals);
+     var plotList = data.filter(function(x) {
+       return $.inArray(x.category, split.nonNumeric) !== -1;
+     });
+     // Build list of plottables and return
+     var plottables = [];
+     for (var i = 0; i < plotList.length; i++) {
+       plottables = plottables.concat(plotList[i].plottables);
+     }
+     return plottables;
+   };
+
+
+  /**
+   *
+   * Wrapper for generating a list of colors that corresponds to all samples
+   * in the plot by coloring type requested
+   *
+   * @param {String[]} values list of objects to generate a color for, usually a
+   * category in a given metadata column.
+   * @param {String} [map = {'discrete-coloring-qiime'|'Viridis'}] name of the
+   * color map to use, see ColorViewController.Colormaps
+   * @see ColorViewController.Colormaps
+   * @param {Boolean} discrete Whether to treat colormap requested as a
+   * discrete set of colors or use interpolation to create gradient of colors
+   * @param {Boolean} [scaled = false] Whether to use a scaled colormap or
+   * equidistant colors for each value
+   * @see ColorViewController.getDiscreteColors
+   * @see ColorViewController.getInterpolatedColors
+   * @see ColorViewController.getScaledColors
+   *
+   * @return {Object} colors The object containing the hex colors keyed to
+   * each sample
+   * @return {String} gradientSVG The SVG string for the scaled data or null
+   *
+   */
+  ColorViewController.getColorList = function(values, map, discrete, scaled) {
+    var colors = {}, gradientSVG;
+    scaled = scaled || false;
+
+    if (_.findWhere(ColorViewController.Colormaps, {id: map}) === undefined) {
+      throw new Error('Could not find ' + map + ' as a colormap.');
+    }
+
+    // 1 color and continuous coloring should return the first element in map
+    if (values.length == 1 && discrete === false) {
+      colors[values[0]] = chroma.brewer[map][0];
+      return [colors, gradientSVG];
+    }
+
+    //Call helper function to create the required colormap type
+    if (discrete) {
+      colors = ColorViewController.getDiscreteColors(values, map);
+    }
+    else if (scaled) {
+      try {
+        var info = ColorViewController.getScaledColors(values, map);
+      } catch (e) {
+        alert('Category can not be shown as continuous values. Continuous ' +
+              'coloration requires at least 2 numeric values in the category.');
+        throw new Error('non-numeric category');
+      }
+      colors = info[0];
+      gradientSVG = info[1];
+    }
+    else {
+      colors = ColorViewController.getInterpolatedColors(values, map);
+    }
+    return [colors, gradientSVG];
+  };
+
+  /**
+   *
+   * Retrieve a discrete color set.
+   *
+   * @param {String[]} values list of objects to generate a color for, usually a
+   * category in a given metadata column.
+   * @param {String} [map = 'discrete-coloring-qiime'] name of the color map to
+   * use, see ColorViewController.Colormaps
+   * @see ColorViewController.Colormaps
+   *
+   * @return {Object} colors The object containing the hex colors keyed to
+   * each sample
+   *
+   */
+  ColorViewController.getDiscreteColors = function(values, map) {
+    map = map || 'discrete-coloring-qiime';
+
+    if (map == 'discrete-coloring-qiime') {
+      map = ColorViewController._qiimeDiscrete;
+    } else {
+      map = chroma.brewer[map];
+    }
+    var size = map.length;
+    var colors = {};
+    for (var i = 0; i < values.length; i++) {
+        mapIndex = i - (Math.floor(i / size) * size);
+        colors[values[i]] = map[mapIndex];
+    }
+    return colors;
+  };
+
+  /**
+   *
+   * Retrieve a scaled color set.
+   *
+   * @param {String[]} values Objects to generate a color for, usually a
+   * category in a given metadata column.
+   * @param {String} [map = 'Viridis'] name of the discrete color map to use.
+   * @param {String} [nanColor = '#64655d'] Color to use for non-numeric values.
+   *
+   * @return {Object} colors The object containing the hex colors keyed to
+   * each sample
+   * @return {String} gradientSVG The SVG string for the scaled data or null
+   *
+   */
+  ColorViewController.getScaledColors = function(values, map, nanColor) {
+    map = map || 'viridis';
+    nanColor = nanColor || '#64655d';
+    map = chroma.brewer[map];
+
+    // Get list of only numeric values, error if none
+    var split = util.splitNumericValues(values);
+    if (split.numeric.length < 2) {
+      throw new Error('non-numeric category');
+    }
+    min = _.min(split.numeric);
+    max = _.max(split.numeric);
+    var interpolator = chroma.scale(map).domain([min, max]);
+    var colors = {};
+
+    // Color all the numeric values
+    _.each(split.numeric, function(element) {
+      colors[element] = interpolator(element).hex();
+    });
+    //Gray out non-numeric values
+    _.each(split.nonNumeric, function(element) {
+      colors[element] = nanColor;
+    });
+    //build the SVG showing the gradient of colors for values
+    var mid = (min + max) / 2;
+    var step = (max - min) / 100;
+    var stopColors = [];
+    for (var s = min; s <= max; s += step) {
+      stopColors.push(interpolator(s).hex());
+    }
+    var gradientSVG = '<defs>';
+    gradientSVG += '<linearGradient id="Gradient" x1="0" x2="0" y1="1" y2="0">';
+    for (var pos = 0; pos < stopColors.length; pos++) {
+      gradientSVG += '<stop offset="' + pos + '%" stop-color="' +
+        stopColors[pos] + '"/>';
+    }
+    gradientSVG += '</linearGradient></defs><rect id="gradientRect" ' +
+      'width="20" height="95%" fill="url(#Gradient)"/>';
+
+    gradientSVG += '<text x="25" y="12px" font-family="sans-serif" ' +
+      'font-size="12px" text-anchor="start">' + max + '</text>';
+    gradientSVG += '<text x="25" y="50%" font-family="sans-serif" ' +
+      'font-size="12px" text-anchor="start">' + mid + '</text>';
+    gradientSVG += '<text x="25" y="95%" font-family="sans-serif" ' +
+      'font-size="12px" text-anchor="start">' + min + '</text>';
+    return [colors, gradientSVG];
+  };
+
+  /**
+   *
+   * Retrieve an interpolatd color set.
+   *
+   * @param {String[]} values Objects to generate a color for, usually a
+   * category in a given metadata column.
+   * @param {String} [map = 'Viridis'] name of the discrete color map to use.
+   *
+   * @return {Object} colors The object containing the hex colors keyed to
+   * each sample.
+   *
+   */
+  ColorViewController.getInterpolatedColors = function(values, map) {
+    map = map || 'viridis';
+    map = chroma.brewer[map];
+
+    var total = values.length;
+    var interpolator = chroma.bezier([map[0], map[3], map[4], map[5], map[8]]);
+    var colors = {};
+    for (var i = 0; i < values.length; i++) {
+      colors[values[i]] = interpolator(i / total).hex();
+    }
+    return colors;
+  };
+
+  /**
+   * Converts the current instance into a JSON string.
+   *
+   * @return {Object} JSON ready representation of self.
+   */
+  ColorViewController.prototype.toJSON = function() {
+    var json = EmperorAttributeABC.prototype.toJSON.call(this);
+    json.colormap = this.$colormapSelect.val();
+    json.continuous = this.$scaled.is(':checked');
+    return json;
+  };
+
+  /**
+   * Decodes JSON string and modifies its own instance variables accordingly.
+   *
+   * @param {Object} Parsed JSON string representation of self.
+   */
+  ColorViewController.prototype.fromJSON = function(json) {
+    // NOTE: We do not call super here because of the non-numeric values issue
+    // Order here is important. We want to set all the extra controller
+    // settings before we load from json, as they can override the JSON when set
+    var data;
+    this.$select.val(json.category);
+    this.$select.trigger('chosen:updated');
+    this.$colormapSelect.val(json.colormap);
+    this.$colormapSelect.trigger('chosen:updated');
+    this.$scaled.prop('checked', json.continuous);
+    this.$scaled.trigger('change');
+
+    // Fetch and set the SlickGrid-formatted data
+    // Need to take into account the existence of the non-numeric values grid
+    // information from the continuous data.
+    var decompViewDict = this.decompViewDict[this.getActiveDecompViewKey()];
+    if (this.$scaled.is(':checked')) {
+      // Get the current SlickGrid data and update with the saved color
+      var data = this.bodyGrid.getData();
+      data[0].value = json.data['Non-numeric values'];
+      this.setPlottableAttributes(
+        decompViewDict, json.data['Non-numeric values'], data[0].plottables);
+
+    }
+    else {
+      var data = decompViewDict.setCategory(
+        json.data, this.setPlottableAttributes, json.category);
+    }
+    this.setSlickGridDataset(data);
+  };
+
+  /**
+   * Resizes the container and the individual elements.
+   *
+   * Note, the consumer of this class, likely the main controller should call
+   * the resize function any time a resizing event happens.
+   *
+   * @param {Float} width the container width.
+   * @param {Float} height the container height.
+   */
+  ColorViewController.prototype.resize = function(width, height) {
+    this.$body.height(this.$canvas.height() - this.$header.height());
+    this.$body.width(this.$canvas.width());
+
+    if (this.$scaled.is(':checked')) {
+      this.$scaleDiv.css('height', (this.$body.height() / 2) + 'px');
+      this.$gridDiv.css('height', (this.$body.height() / 2 - 20) + 'px');
+    }
+    else {
+      this.$gridDiv.css('height', '100%');
+    }
+    // call super, most of the header and body resizing logic is done there
+    EmperorAttributeABC.prototype.resize.call(this, width, height);
+  };
+
+  /**
+   * Helper function to set the color of plottable
+   *
+   * @param {scope} object , the scope where the plottables exist
+   * @param {color} string , hexadecimal representation of a color, which will
+   * be applied to the plottables
+   * @param {group} array of objects, list of object that should be changed in
+   * scope
+   */
+  ColorViewController.prototype.setPlottableAttributes =
+  function(scope, color, group) {
+    var idx;
+
+    _.each(group, function(element) {
+      idx = element.idx;
+      scope.markers[idx].material.color = new THREE.Color(color);
+    });
+    scope.needsUpdate = true;
+  };
+
+  var DISCRETE = 'Discrete';
+  var SEQUENTIAL = 'Sequential';
+  var DIVERGING = 'Diverging';
+  /**
+   * @type {Object}
+   * Color maps available, along with what type of colormap they are.
+   */
+  ColorViewController.Colormaps = [
+    {id: 'discrete-coloring-qiime', name: 'Classic QIIME Colors',
+     type: DISCRETE},
+    {id: 'Paired', name: 'Paired', type: DISCRETE},
+    {id: 'Accent', name: 'Accent', type: DISCRETE},
+    {id: 'Dark2', name: 'Dark', type: DISCRETE},
+    {id: 'Set1', name: 'Set1', type: DISCRETE},
+    {id: 'Set2', name: 'Set2', type: DISCRETE},
+    {id: 'Set3', name: 'Set3', type: DISCRETE},
+    {id: 'Pastel1', name: 'Pastel1', type: DISCRETE},
+    {id: 'Pastel2', name: 'Pastel2', type: DISCRETE},
+
+    {id: 'Viridis', name: 'Viridis', type: SEQUENTIAL},
+    {id: 'Reds', name: 'Reds', type: SEQUENTIAL},
+    {id: 'RdPu', name: 'Red-Purple', type: SEQUENTIAL},
+    {id: 'Oranges', name: 'Oranges', type: SEQUENTIAL},
+    {id: 'OrRd', name: 'Orange-Red', type: SEQUENTIAL},
+    {id: 'YlOrBr', name: 'Yellow-Orange-Brown', type: SEQUENTIAL},
+    {id: 'YlOrRd', name: 'Yellow-Orange-Red', type: SEQUENTIAL},
+    {id: 'YlGn', name: 'Yellow-Green', type: SEQUENTIAL},
+    {id: 'YlGnBu', name: 'Yellow-Green-Blue', type: SEQUENTIAL},
+    {id: 'Greens', name: 'Greens', type: SEQUENTIAL},
+    {id: 'GnBu', name: 'Green-Blue', type: SEQUENTIAL},
+    {id: 'Blues', name: 'Blues', type: SEQUENTIAL},
+    {id: 'BuGn', name: 'Blue-Green', type: SEQUENTIAL},
+    {id: 'BuPu', name: 'Blue-Purple', type: SEQUENTIAL},
+    {id: 'Purples', name: 'Purples', type: SEQUENTIAL},
+    {id: 'PuRd', name: 'Purple-Red', type: SEQUENTIAL},
+    {id: 'PuBuGn', name: 'Purple-Blue-Green', type: SEQUENTIAL},
+    {id: 'Greys', name: 'Greys', type: SEQUENTIAL},
+
+    {id: 'Spectral', name: 'Spectral', type: DIVERGING},
+    {id: 'RdBu', name: 'Red-Blue', type: DIVERGING},
+    {id: 'RdYlGn', name: 'Red-Yellow-Green', type: DIVERGING},
+    {id: 'RdYlB', name: 'Red-Yellow-Blue', type: DIVERGING},
+    {id: 'RdGy', name: 'Red-Grey', type: DIVERGING},
+    {id: 'PiYG', name: 'Pink-Yellow-Green', type: DIVERGING},
+    {id: 'BrBG', name: 'Brown-Blue-Green', type: DIVERGING},
+    {id: 'PuOr', name: 'Purple-Orange', type: DIVERGING},
+    {id: 'PRGn', name: 'Purple-Green', type: DIVERGING}
+  ];
+
+  // taken from the qiime/colors.py module; a total of 24 colors
+  /** @private */
+  ColorViewController._qiimeDiscrete = ['#ff0000', '#0000ff', '#f27304',
+  '#008000', '#91278d', '#ffff00', '#7cecf4', '#f49ac2', '#5da09e', '#6b440b',
+  '#808080', '#f79679', '#7da9d8', '#fcc688', '#80c99b', '#a287bf', '#fff899',
+  '#c49c6b', '#c0c0c0', '#ed008a', '#00b6ff', '#a54700', '#808000', '#008080'];
+
+  return ColorViewController;
+});
diff --git a/emperor/support_files/js/controller.js b/emperor/support_files/js/controller.js
new file mode 100644
index 0000000..0f67685
--- /dev/null
+++ b/emperor/support_files/js/controller.js
@@ -0,0 +1,617 @@
+define([
+    'jquery',
+    'underscore',
+    'contextmenu',
+    'three',
+    'view',
+    'scene3d',
+    'colorviewcontroller',
+    'visibilitycontroller',
+    'shapecontroller',
+    'axescontroller',
+    'scaleviewcontroller',
+    'filesaver',
+    'svgrenderer',
+    'draw'
+], function($, _, contextMenu, THREE, DecompositionView, ScenePlotView3D,
+             ColorViewController, VisibilityController, ShapeController,
+             AxesController, ScaleViewController, FileSaver, SVGRenderer,
+             Draw) {
+
+  /**
+   *
+   * @class EmperorController
+   *       This is the application controller
+   *
+   * The application controller, contains all the information on how the model
+   * is being presented to the user.
+   *
+   * @param {DecompositionModel} dm An object that will be represented on
+   * screen.
+   * @param {string} divId The element id where the controller should
+   * instantiate itself.
+   * @param {node} [webglcanvas = undefined] the canvas to use to render the
+   * information. This parameter is optional, and should rarely be set. But is
+   * useful for external applications like SAGE2.
+   *
+   * @return {EmperorController}
+   * @constructs EmperorController
+   *
+   */
+  function EmperorController(dm, divId, webglcanvas) {
+    var scope = this;
+
+    /**
+     * Scaling constant for grid dimensions (read only).
+     * @type {float}
+     */
+    this.GRID_SCALE = 0.97;
+
+    /**
+     * Scaling constant for scene plot view dimensions
+     * @type {float}
+     */
+    this.SCENE_VIEW_SCALE = 0.5;
+    /**
+     * jQuery object where the object lives in.
+     * @type {node}
+     */
+    this.$divId = $('#' + divId);
+    /**
+     * Width of the object.
+     * @type {float}
+     */
+    this.width = this.$divId.width();
+    /**
+     * Height of the object.
+     * @type {float}
+     */
+    this.height = this.$divId.height();
+
+    /**
+     * Ordination data being plotted.
+     * @type {DecompositionModel}
+     */
+    this.dm = dm;
+    /**
+     * List of the scene plots views being rendered.
+     * @type {ScenePlotView3D[]}
+     */
+    this.sceneViews = [];
+
+    /**
+     * Internal div where the menus live in (jQuery object).
+     * @type {node}
+     */
+    this.$plotSpace = $("<div class='emperor-plot-wrapper'></div>");
+    /**
+     * Internal div where the plots live in (jQuery object).
+     * @type {node}
+     */
+    this.$plotMenu = $("<div class='emperor-plot-menu'></div>");
+
+    this.$divId.append(this.$plotSpace);
+    this.$divId.append(this.$plotMenu);
+
+    /**
+     * Holds a reference to all the tabs (view controllers) in the `$plotMenu`.
+     * @type {object}
+     */
+    this.controllers = {};
+
+    /**
+     * Background color of the scene.
+     * @type {THREE.Color}
+     * @default 0x00000000
+     */
+    this.rendererBackgroundColor = new THREE.Color();
+    this.rendererBackgroundColor.setHex('0x000000');
+
+    /**
+     * Object in charge of doing the rendering of the scenes.
+     * @type {THREE.Renderer}
+     */
+    this.renderer = null;
+    if (webglcanvas !== undefined) {
+        this.renderer = new THREE.WebGLRenderer({canvas: webglcanvas,
+                                                 antialias: true});
+    }
+    else {
+        this.renderer = new THREE.WebGLRenderer({antialias: true});
+    }
+
+    this.renderer.setSize(this.width, this.height);
+    this.renderer.setClearColor(this.rendererBackgroundColor);
+    this.renderer.autoClear = false;
+    this.renderer.sortObjects = true;
+    this.$plotSpace.append(this.renderer.domElement);
+
+    /**
+     * Menu tabs containers, note that we need them in this format to have
+     * jQuery's UI tabs work properly. All the view controllers will be added
+     * to this container, see the addTab method
+     * @see EmperorController.addTab
+     * @type {node}
+     * @private
+     */
+    this._$tabsContainer = $("<div name='emperor-tabs-container'></div>");
+    this._$tabsContainer.css('background-color', '#EEEEEE');
+    /**
+     * List of available tabs, lives inside `_$tabsContainer`.
+     * @type {node}
+     * @private
+     */
+    this._$tabsList = $("<ul name='emperor-tabs-list'></ul>");
+
+    // These will both live in the menu space. As of the writing of this code
+    // there's nothing else but tabs on the menu, but this may change in the
+    // future, that's why we are creating the extra "tabsContainer" div
+    this.$plotMenu.append(this._$tabsContainer);
+    this._$tabsContainer.append(this._$tabsList);
+
+    /**
+     * Object with all the available decomposition views.
+     *
+     * FIXME: This is a hack to go around the fact that the constructor takes
+     * a single decomposition model instead of a dictionary
+     *
+     * @type {object}
+     */
+    this.decViews = {'scatter': new DecompositionView(this.dm)};
+
+    // default decomposition view uses the full window
+    this.addView();
+
+    $(function() {
+      scope._buildUI();
+      // Hide the loading splashscreen
+      scope.$divId.find('.loading').hide();
+    });
+
+    // once the object finishes loading, resize the contents so everything fits
+    // nicely
+    $(this).ready(function() {
+      scope.resize(scope.$divId.width(), scope.$divId.height());
+    });
+
+  };
+
+  /**
+   *
+   * Helper method to add additional ScenePlotViews (i.e. another plot)
+   *
+   */
+  EmperorController.prototype.addView = function() {
+    if (this.sceneViews.length > 4) {
+      throw Error('Cannot add another scene plot view');
+    }
+
+    var spv = new ScenePlotView3D(this.renderer, this.decViews,
+                                  this.$plotSpace, 0, 0, 0, 0);
+    this.sceneViews.push(spv);
+
+    // this will setup the appropriate sizes and widths
+    this.resize(this.width, this.height);
+  };
+
+  /**
+   *
+   * Helper method to resize the plots
+   *
+   * @param {width} the width of the entire plotting space
+   * @param {height} the height of the entire plotting space
+   *
+   */
+  EmperorController.prototype.resize = function(width, height) {
+    // update the available space we have
+    this.width = width;
+    this.height = height;
+
+    this.$plotSpace.height(height);
+    this.$plotMenu.height(height);
+
+    this._$tabsContainer.height(height);
+
+    // the area we have to present the plot is smaller than the total
+    var plotWidth = this.$plotSpace.width();
+
+    // TODO: The below will need refactoring
+    // This is addressed in issue #405
+    if (this.sceneViews.length === 1) {
+      this.sceneViews[0].resize(0, 0, plotWidth, this.height);
+    }
+    else if (this.sceneViews.length === 2) {
+      this.sceneViews[0].resize(0, 0, this.SCENE_VIEW_SCALE * plotWidth,
+          this.height);
+      this.sceneViews[1].resize(this.SCENE_VIEW_SCALE * plotWidth, 0,
+          this.SCENE_VIEW_SCALE * plotWidth, this.height);
+    }
+    else if (this.sceneViews.length === 3) {
+      this.sceneViews[0].resize(0, 0,
+          this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+      this.sceneViews[1].resize(this.SCENE_VIEW_SCALE * plotWidth, 0,
+          this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+      this.sceneViews[2].resize(0, this.SCENE_VIEW_SCALE * this.height,
+          plotWidth, this.SCENE_VIEW_SCALE * this.height);
+    }
+    else if (this.sceneViews.length === 4) {
+      this.sceneViews[0].resize(0, 0, this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+      this.sceneViews[1].resize(this.SCENE_VIEW_SCALE * plotWidth, 0,
+          this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+      this.sceneViews[2].resize(0, this.SCENE_VIEW_SCALE * this.height,
+          this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+      this.sceneViews[3].resize(this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height,
+          this.SCENE_VIEW_SCALE * plotWidth,
+          this.SCENE_VIEW_SCALE * this.height);
+    }
+    else {
+      throw Error('More than four views are currently not supported');
+    }
+
+    this.renderer.setSize(plotWidth, this.height);
+
+    /* Resizing the tabs (view controllers) */
+
+    // resize the grid according to the size of the container, since we are
+    // inside the tabs we have to account for that lost space.
+    var tabHeight = this.$plotMenu.height() * this.GRID_SCALE;
+
+    // the tab list at the top takes up a variable amount of space and
+    // without this, the table displayed below will have an odd scrolling
+    // behaviour
+    tabHeight -= this._$tabsList.height();
+
+    // for each controller, we need to (1) trigger the resize method, and (2)
+    // resize the height of the containing DIV tag (we don't need to resize the
+    // width as this is already taken care of since it just has to fit the
+    // available space).
+    _.each(this.controllers, function(controller, index) {
+      if (controller !== undefined) {
+        $('#' + controller.identifier).height(tabHeight);
+
+        var w = $('#' + controller.identifier).width(),
+            h = $('#' + controller.identifier).height();
+
+        controller.resize(w, h);
+      }
+    });
+
+    //Set all scenes to needing update
+    for (var i = 0; i < this.sceneViews.length; i++) {
+      this.sceneViews[i].needsUpdate = true;
+    }
+  };
+
+  /**
+   *
+   * Helper method to render sceneViews, gets called every time the browser
+   * indicates we can render a new frame, however it only triggers the
+   * appropriate rendering functions if something has changed since the last
+   * frame.
+   *
+   */
+  EmperorController.prototype.render = function() {
+    var scope = this;
+    $.each(this.sceneViews, function(i, sv) {
+      if (sv.checkUpdate()) {
+        scope.renderer.setViewport(0, 0, scope.width, scope.height);
+        scope.renderer.clear();
+        sv.render();
+      }
+    });
+  };
+
+  /**
+   *
+   * Helper method to assemble UI, completely independent of HTML template.
+   * This method is called when the object is constructed.
+   *
+   * @private
+   *
+   */
+  EmperorController.prototype._buildUI = function() {
+    var scope = this;
+
+    //FIXME: This only works for 1 scene plot view
+    this.controllers.color = this.addTab(this.sceneViews[0].decViews,
+                                         ColorViewController);
+    this.controllers.visibility = this.addTab(this.sceneViews[0].decViews,
+                                              VisibilityController);
+    this.controllers.shape = this.addTab(this.sceneViews[0].decViews,
+                                         ShapeController);
+    this.controllers.axes = this.addTab(this.sceneViews[0].decViews,
+                                        AxesController);
+    this.controllers.scale = this.addTab(this.sceneViews[0].decViews,
+        ScaleViewController);
+
+    // We are tabifying this div, I don't know man.
+    this._$tabsContainer.tabs({heightStyle: 'fill',
+                               // The tabs on the plot space only get resized
+                               // when they are visible, thus we subscribe to
+                               // the event that's fired after a user selects a
+                               // tab.  If you don't do this, the width and
+                               // height of each of the view controllers will
+                               // be wrong.  We also found that subscribing to
+                               // document.ready() wouldn't work either as the
+                               // resize callback couldn't be executed on a tab
+                               // that didn't exist yet.
+                               activate: function(event, ui) {
+                                 scope.resize(scope.$divId.width(),
+                                              scope.$divId.height());
+                               }});
+
+    // Set up the context menu
+    this.$contextMenu = $.contextMenu({
+      // only tie this selector to our own container div, otherwise with
+      // multiple plots on the same screen, this callback gets confused
+      selector: '#' + scope.$divId.attr('id') + ' .emperor-plot-wrapper',
+      trigger: 'none',
+      items: {
+        'toggleAutorotate': {
+          name: 'Toggle autorotation',
+          icon: 'rotate-left',
+          callback: function(key, opts) {
+            _.each(scope.sceneViews, function(scene) {
+              scene.control.autoRotate = scene.control.autoRotate ^ true;
+            });
+          }
+        },
+        'sep0': '----------------',
+        'saveState': {
+          name: 'Save current settings',
+          icon: 'save',
+          callback: function(key, opts) {
+            scope.saveConfig();
+          }
+        },
+        'loadState': {
+          name: 'Load saved settings',
+          icon: 'folder-open-o',
+          callback: function(key, opts) {
+            if (!FileReader) {
+              alert('Your browser does not support file loading. We ' +
+                    'recommend using Google Chrome for full functionality.');
+              return;
+            }
+            var file = $('<input type="file">');
+            file.on('change', function(evt) {
+              var f = evt.target.files[0];
+              // With help from
+              // http://www.htmlgoodies.com/beyond/javascript/read-text-files-using-the-javascript-filereader.html
+              var r = new FileReader();
+              r.onload = function(e) {
+                try {
+                  var json = JSON.parse(e.target.result);
+                } catch (err) {
+                  alert('File given is not a JSON parsable file.');
+                  return;
+                }
+                try {
+                  scope.loadConfig(json);
+                } catch (err) {
+                  alert('Error loading settings from file: ' + err.message);
+                  return;
+                }
+              };
+              r.readAsText(f);
+            });
+            file.click();
+          }
+        },
+        'sep1': '---------',
+        'fold1': {
+            'name': 'Save Image',
+            icon: 'file-picture-o',
+            'items': {
+              'saveImagePNG': {
+                name: 'PNG',
+                callback: function(key, opts) {
+                  scope.screenshot('png');
+                }
+              },
+              'saveImageSVG': {
+                name: 'SVG + labels',
+                callback: function(key, opts) {
+                  scope.screenshot('svg');
+                }
+              }
+            }
+        },
+      }
+    });
+
+    // Add shift+right click as the trigger for the context menu
+    this.$plotSpace.on('contextmenu', function(e) {
+      if (e.shiftKey) {
+        var contextDiv = $('#' + scope.$divId.attr('id') +
+                           ' .emperor-plot-wrapper');
+        contextDiv.contextMenu({x: e.pageX, y: e.pageY});
+      }
+    });
+  };
+
+  /**
+   *
+   * Save the current canvas view to a new window
+   *
+   * @param {string} [type = png] Format to save the file as: ('png', 'svg')
+   *
+   */
+  EmperorController.prototype.screenshot = function(type) {
+    type = type || 'png';
+
+    if (type === 'png') {
+      // Render all scenes so it's rendered in same context as save
+      for (var i = 0; i < this.sceneViews.length; i++) {
+        this.sceneViews[i].render();
+      }
+      var c = this.renderer.domElement.toDataURL('image/' + type);
+      // Create DOM-less download link and click it to start download
+      var download = $('<a href="' + c + '" download="emperor.' + type + '">');
+      download.get(0).click();
+    } else if (type === 'svg') {
+      // confirm box based on number of samples: better safe than sorry
+      if (this.dm.length >= 9000) {
+        if (confirm('This number of samples could take a long time and in ' +
+           'some computers the browser will crash. If this happens we ' +
+           'suggest to use the png implementation. Do you want to ' +
+           'continue?') == false) {
+          return;
+        }
+      }
+
+      // generating SVG image
+      var svgRenderer = new THREE.SVGRenderer({antialias: true,
+                                               preserveDrawingBuffer: true});
+      svgRenderer.setSize(this.$plotSpace.width(), this.$plotSpace.height());
+      svgRenderer.setClearColor(this.renderer.getClearColor(), 1);
+      svgRenderer.render(this.sceneViews[0].scene, this.sceneViews[0].camera);
+      svgRenderer.sortObjects = true;
+
+      // converting svgRenderer to string: http://stackoverflow.com/a/17415624
+      var XMLS = new XMLSerializer();
+      var svgfile = XMLS.serializeToString(svgRenderer.domElement);
+
+      // some browsers (Chrome) will add the namespace, some won't. Make sure
+      // that if it's not there, you add it to make sure the file can be opened
+      // in tools like Adobe Illustrator or in browsers like Safari or FireFox
+      if (svgfile.indexOf('xmlns="http://www.w3.org/2000/svg"') === -1) {
+        // adding xmlns header to open in the browser
+        svgfile = svgfile.replace('viewBox=',
+                                  'xmlns="http://www.w3.org/2000/svg" ' +
+                                  'viewBox=');
+      }
+
+      // hacking the background color by adding a rectangle
+      var index = svgfile.indexOf('viewBox="') + 9;
+      var viewBox = svgfile.substring(index,
+                                      svgfile.indexOf('"', index)).split(' ');
+      var background = '<rect id="background" height="' + viewBox[3] +
+                       '" width="' + viewBox[2] + '" y="' + viewBox[1] +
+                       '" x="' + viewBox[0] +
+                       '" stroke-width="0" stroke="#000000" fill="#' +
+                       this.renderer.getClearColor().getHexString() + '"/>';
+      index = svgfile.indexOf('>', index) + 1;
+      svgfile = svgfile.substr(0, index) + background + svgfile.substr(index);
+
+      var blob = new Blob([svgfile], {type: 'image/svg+xml'});
+      saveAs(blob, 'emperor-image.svg');
+
+      // generating legend
+      var names = [], colors = [];
+      _.each(this.controllers.color.bodyGrid.getData(), function(element) {
+        names.push(element.category);
+        colors.push(element.value);
+      });
+      var blob = new Blob([Draw.formatSVGLegend(names, colors)],
+                          {type: 'image/svg+xml'});
+      saveAs(blob, 'emperor-image-labels.svg');
+    } else {
+      console.error();('Screenshot type not implemented');
+    }
+  };
+
+  /**
+   *
+   * Write settings file for the current controller settings
+   *
+   * The format is as follows: a javascript object with the camera position
+   * stored in the 'cameraPosition' key and the quaternion in the
+   * 'cameraQuaternion' key. Each controller in this.controllers is then saved
+   * by calling toJSON on them, and the resulting object saved under the same
+   * key as the controllers object.
+   *
+   */
+   EmperorController.prototype.saveConfig = function() {
+    var saveinfo = {};
+    // Assuming single sceneview for now
+    sceneview = this.sceneViews[0];
+    saveinfo.cameraPosition = sceneview.camera.position;
+    saveinfo.cameraQuaternion = sceneview.camera.quaternion;
+    // Save settings for each controller in the view
+     _.each(this.controllers, function(controller, index) {
+      if (controller !== undefined) {
+        saveinfo[index] = controller.toJSON();
+      }
+    });
+
+    // Save the file
+    var blob = new Blob([JSON.stringify(saveinfo)], {type: 'text/json'});
+    saveAs(blob, 'emperor-settings.json');
+   };
+
+  /**
+   *
+   * Load a settings file and set all controller variables.
+   *
+   * This method will trigger a rendering callback.
+   *
+   * @param {object} json Information about the emperor session to load.
+   *
+   */
+   EmperorController.prototype.loadConfig = function(json) {
+    //still assuming one sceneview for now
+    var sceneview = this.sceneViews[0];
+
+    sceneview.camera.position.set(json.cameraPosition.x,
+                                  json.cameraPosition.y,
+                                  json.cameraPosition.z);
+    sceneview.camera.quaternion.set(json.cameraQuaternion._x,
+                                    json.cameraQuaternion._y,
+                                    json.cameraQuaternion._z,
+                                    json.cameraQuaternion._w);
+
+    //must call updates to reset for camera move
+    sceneview.camera.updateProjectionMatrix();
+    sceneview.control.update();
+
+    //load the rest of the controller settings
+     _.each(this.controllers, function(controller, index) {
+      if (controller !== undefined) {
+        controller.fromJSON(json[index]);
+      }
+    });
+    sceneview.needsUpdate = true;
+   };
+
+  /**
+   *
+   * Helper method to resize the plots.
+   *
+   * @param {DecompositionView[]} dvdict Dictionary of DecompositionViews.
+   * @param {EmperorViewControllerABC} viewConstructor Constructor of the view
+   * controller.
+   *
+   */
+  EmperorController.prototype.addTab = function(dvdict, viewConstructor) {
+    // nothing but a temporary id
+    var id = (Math.round(1000000 * Math.random())).toString();
+
+    this._$tabsContainer.append("<div id='" + id +
+                                "' class='emperor-tab-div' ></div>");
+    $('#' + id).height(this.$plotMenu.height() - this._$tabsList.height());
+
+    // dynamically instantiate the controller, see:
+    // http://stackoverflow.com/a/8843181
+    var params = [null, '#' + id, dvdict];
+    var obj = new (Function.prototype.bind.apply(viewConstructor, params));
+
+    // set the identifier of the div to the one defined by the object
+    $('#' + id).attr('id', obj.identifier);
+
+    // now add the list element linking to the container div with the proper
+    // title
+    this._$tabsList.append("<li><a href='#" + obj.identifier + "'>" +
+                           obj.title + '</a></li>');
+
+    return obj;
+  };
+
+  return EmperorController;
+});
diff --git a/emperor/support_files/js/d3.parcoords.js b/emperor/support_files/js/d3.parcoords.js
deleted file mode 100644
index 3a75e2c..0000000
--- a/emperor/support_files/js/d3.parcoords.js
+++ /dev/null
@@ -1,568 +0,0 @@
-d3.parcoords = function(config) {
-  var __ = {
-    data: [],
-    dimensions: [],
-    types: {},
-    brushed: false,
-    mode: "default",
-    rate: 20,
-    width: 600,
-    height: 300,
-    margin: { top: 24, right: 0, bottom: 12, left: 0 },
-    color: "#069",
-    composite: "source-over",
-    alpha: 0.7
-  };
-
-  extend(__, config);
-var pc = function(selection) {
-  selection = pc.selection = d3.select(selection);
-
-  __.width = selection[0][0].clientWidth;
-  __.height = selection[0][0].clientHeight;
-
-  // canvas data layers
-  ["shadows", "marks", "foreground", "highlight"].forEach(function(layer) {
-    canvas[layer] = selection
-      .append("canvas")
-      .attr("class", layer)[0][0];
-    ctx[layer] = canvas[layer].getContext("2d");
-  });
-
-  // svg tick and brush layers
-  pc.svg = selection
-    .append("svg")
-      .attr("width", __.width)
-      .attr("height", __.height)
-    .append("svg:g")
-      .attr("transform", "translate(" + __.margin.left + "," + __.margin.top + ")");
-
-  return pc;
-};
-var events = d3.dispatch.apply(this,["render", "resize", "highlight", "brush"].concat(d3.keys(__))),
-    w = function() { return __.width - __.margin.right - __.margin.left; },
-    h = function() { return __.height - __.margin.top - __.margin.bottom },
-    flags = {
-      brushable: false,
-      reorderable: false,
-      axes: false,
-      interactive: false,
-      shadows: false,
-      debug: false
-    },
-    xscale = d3.scale.ordinal(),
-    yscale = {},
-    dragging = {},
-    line = d3.svg.line(),
-    axis = d3.svg.axis().orient("left").ticks(5),
-    g, // groups for axes, brushes
-    ctx = {},
-    canvas = {};
-
-// side effects for setters
-var side_effects = d3.dispatch.apply(this,d3.keys(__))
-  .on("composite", function(d) { ctx.foreground.globalCompositeOperation = d.value; })
-  .on("alpha", function(d) { ctx.foreground.globalAlpha = d.value; })
-  .on("width", function(d) { pc.resize(); })
-  .on("height", function(d) { pc.resize(); })
-  .on("margin", function(d) { pc.resize(); })
-  .on("rate", function(d) { rqueue.rate(d.value); })
-  .on("data", function(d) {
-    if (flags.shadows) paths(__.data, ctx.shadows);
-  })
-  .on("dimensions", function(d) {
-    xscale.domain(__.dimensions);
-    if (flags.interactive) pc.render().updateAxes();
-  });
-
-// expose the state of the chart
-pc.state = __;
-pc.flags = flags;
-
-// create getter/setters
-getset(pc, __, events);
-
-// expose events
-d3.rebind(pc, events, "on");
-
-// tick formatting
-d3.rebind(pc, axis, "ticks", "orient", "tickValues", "tickSubdivide", "tickSize", "tickPadding", "tickFormat");
-
-// getter/setter with event firing
-function getset(obj,state,events)  {
-  d3.keys(state).forEach(function(key) {
-    obj[key] = function(x) {
-      if (!arguments.length) return state[key];
-      var old = state[key];
-      state[key] = x;
-      side_effects[key].call(pc,{"value": x, "previous": old});
-      events[key].call(pc,{"value": x, "previous": old});
-      return obj;
-    };
-  });
-};
-
-function extend(target, source) {
-  for (key in source) {
-    target[key] = source[key];
-  }
-  return target;
-};
-pc.autoscale = function() {
-  // yscale
-  var defaultScales = {
-    "number": function(k) {
-      return d3.scale.linear()
-        .domain(d3.extent(__.data, function(d) { return +d[k]; }))
-        .range([h()+1, 1])
-    },
-    "string": function(k) {
-      return d3.scale.ordinal()
-        .domain(__.data.map(function(p) { return p[k]; }))
-        .rangePoints([h()+1, 1])
-    }
-  };
-
-  __.dimensions.forEach(function(k) {
-    yscale[k] = defaultScales[__.types[k]](k);
-  });
-
-  // hack to remove ordinal dimensions with many values
-  pc.dimensions(pc.dimensions().filter(function(p,i) {
-    var uniques = yscale[p].domain().length;
-    if (__.types[p] == "string" && (uniques > 60 || uniques < 2)) {
-      return false;
-    }
-    return true;
-  }));
-
-  // xscale
-  xscale.rangePoints([0, w()], 1);
-
-  // canvas sizes
-  pc.selection.selectAll("canvas")
-      .style("margin-top", __.margin.top + "px")
-      .style("margin-left", __.margin.left + "px")
-      .attr("width", w()+2)
-      .attr("height", h()+2)
-
-  // default styles, needs to be set when canvas width changes
-  ctx.foreground.strokeStyle = __.color;
-  ctx.foreground.lineWidth = 1.4;
-  ctx.foreground.globalCompositeOperation = __.composite;
-  ctx.foreground.globalAlpha = __.alpha;
-  ctx.highlight.lineWidth = 3;
-  ctx.shadows.strokeStyle = "#dadada";
-
-  return this;
-};
-pc.detectDimensions = function() {
-  pc.types(pc.detectDimensionTypes(__.data));
-  pc.dimensions(d3.keys(pc.types()));
-  return this;
-};
-
-// a better "typeof" from this post: http://stackoverflow.com/questions/7390426/better-way-to-get-type-of-a-javascript-variable
-pc.toType = function(v) {
-  return ({}).toString.call(v).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
-};
-
-// try to coerce to number before returning type
-pc.toTypeCoerceNumbers = function(v) {
-  if ((parseFloat(v) == v) && (v != null)) return "number";
-  return pc.toType(v);
-};
-
-// attempt to determine types of each dimension based on first row of data
-pc.detectDimensionTypes = function(data) {
-  var types = {}
-  d3.keys(data[0])
-    .forEach(function(col) {
-      types[col] = pc.toTypeCoerceNumbers(data[0][col]);
-    });
-  return types;
-};
-pc.render = function() {
-  // try to autodetect dimensions and create scales
-  if (!__.dimensions.length) pc.detectDimensions();
-  if (!(__.dimensions[0] in yscale)) pc.autoscale();
-
-  pc.render[__.mode]();
-
-  events.render.call(this);
-  return this;
-};
-
-pc.render.default = function() {
-  pc.clear('foreground');
-  if (__.brushed) {
-    __.brushed.forEach(path_foreground);
-  } else {
-    __.data.forEach(path_foreground);
-  }
-};
-
-var rqueue = d3.renderQueue(path_foreground)
-  .rate(50)
-  .clear(function() { pc.clear('foreground'); });
-
-pc.render.queue = function() {
-  if (__.brushed) {
-    rqueue(__.brushed);
-  } else {
-    rqueue(__.data);
-  }
-};
-pc.shadows = function() {
-  flags.shadows = true;
-  if (__.data.length > 0) paths(__.data, ctx.shadows);
-  return this;
-};
-
-// draw little dots on the axis line where data intersects
-pc.axisDots = function() {
-  var ctx = pc.ctx.marks;
-  ctx.globalAlpha = d3.min([1/Math.pow(data.length, 1/2), 1]);
-  __.data.forEach(function(d) {
-    __.dimensions.map(function(p,i) {
-      ctx.fillRect(position(p)-0.75,yscale[p](d[p])-0.75,1.5,1.5);
-    });
-  });
-  return this;
-};
-
-// draw single polyline
-function color_path(d, ctx) {
-  ctx.strokeStyle = d3.functor(__.color)(d);
-  ctx.beginPath();
-  __.dimensions.map(function(p,i) {
-    if (i == 0) {
-      ctx.moveTo(position(p),yscale[p](d[p]));
-    } else {
-      ctx.lineTo(position(p),yscale[p](d[p]));
-    }
-  });
-  ctx.stroke();
-};
-
-// draw many polylines of the same color
-function paths(data, ctx) {
-  ctx.clearRect(-1,-1,w()+2,h()+2);
-  ctx.beginPath();
-  data.forEach(function(d) {
-    __.dimensions.map(function(p,i) {
-      if (i == 0) {
-        ctx.moveTo(position(p),yscale[p](d[p]));
-      } else {
-        ctx.lineTo(position(p),yscale[p](d[p]));
-      }
-    });
-  });
-  ctx.stroke();
-};
-
-function path_foreground(d) {
-  return color_path(d, ctx.foreground);
-};
-
-function path_highlight(d) {
-  return color_path(d, ctx.highlight);
-};
-pc.clear = function(layer) {
-  ctx[layer].clearRect(0,0,w()+2,h()+2);
-  return this;
-};
-pc.createAxes = function() {
-  if (g) pc.removeAxes();
-
-  // Add a group element for each dimension.
-  g = pc.svg.selectAll(".dimension")
-      .data(__.dimensions, function(d) { return d; })
-    .enter().append("svg:g")
-      .attr("class", "dimension")
-      .attr("transform", function(d) { return "translate(" + xscale(d) + ")"; })
-
-  // Add an axis and title.
-  g.append("svg:g")
-      .attr("class", "axis")
-      .attr("transform", "translate(0,0)")
-      .each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
-    .append("svg:text")
-      .attr({
-        "text-anchor": "middle",
-        "y": 0,
-        "transform": "translate(0,-12)",
-        "x": 0,
-        "class": "label"
-      })
-      .text(String)
-
-  flags.axes= true;
-  return this;
-};
-
-pc.removeAxes = function() {
-  g.remove();
-  return this;
-};
-
-pc.updateAxes = function() {
-  var g_data = pc.svg.selectAll(".dimension")
-      .data(__.dimensions, function(d) { return d; })
-
-  g_data.enter().append("svg:g")
-      .attr("class", "dimension")
-      .attr("transform", function(p) { return "translate(" + position(p) + ")"; })
-      .style("opacity", 0)
-      .append("svg:g")
-      .attr("class", "axis")
-      .attr("transform", "translate(0,0)")
-      .each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
-    .append("svg:text")
-      .attr({
-        "text-anchor": "middle",
-        "y": 0,
-        "transform": "translate(0,-12)",
-        "x": 0,
-        "class": "label"
-      })
-      .text(String);
-
-  g_data.exit().remove();
-
-  g = pc.svg.selectAll(".dimension");
-
-  g.transition().duration(1100)
-    .attr("transform", function(p) { return "translate(" + position(p) + ")"; })
-    .style("opacity", 1)
-  if (flags.shadows) paths(__.data, ctx.shadows);
-  return this;
-};
-
-pc.brushable = function() {
-  if (!g) pc.createAxes();
-
-  // Add and store a brush for each axis.
-  g.append("svg:g")
-      .attr("class", "brush")
-      .each(function(d) {
-        d3.select(this).call(
-          yscale[d].brush = d3.svg.brush()
-            .y(yscale[d])
-            .on("brush", pc.brush)
-        );
-      })
-    .selectAll("rect")
-      .style("visibility", null)
-      .attr("x", -15)
-      .attr("width", 30)
-  flags.brushable = true;
-  return this;
-};
-
-// Jason Davies, http://bl.ocks.org/1341281
-pc.reorderable = function() {
-  if (!g) pc.createAxes();
-
-  g.style("cursor", "move")
-    .call(d3.behavior.drag()
-      .on("dragstart", function(d) {
-        dragging[d] = this.__origin__ = xscale(d);
-      })
-      .on("drag", function(d) {
-        dragging[d] = Math.min(w(), Math.max(0, this.__origin__ += d3.event.dx));
-        __.dimensions.sort(function(a, b) { return position(a) - position(b); });
-        xscale.domain(__.dimensions);
-        pc.render();
-        g.attr("transform", function(d) { return "translate(" + position(d) + ")"; })
-      })
-      .on("dragend", function(d) {
-        delete this.__origin__;
-        delete dragging[d];
-        d3.select(this).transition().attr("transform", "translate(" + xscale(d) + ")");
-        pc.render();
-      }));
-  flags.reorderable = true;
-  return this;
-};
-
-// pairs of adjacent dimensions
-pc.adjacent_pairs = function(arr) {
-  var ret = [];
-  for (var i = 0; i < arr.length-1; i++) {
-    ret.push([arr[i],arr[i+1]]);
-  };
-  return ret;
-};
-pc.interactive = function() {
-  flags.interactive = true;
-  return this;
-};
-
-// Get data within brushes
-pc.brush = function() {
-  __.brushed = selected();
-  events.brush.call(pc,__.brushed);
-  pc.render();
-};
-
-// expose a few objects
-pc.xscale = xscale;
-pc.yscale = yscale;
-pc.ctx = ctx;
-pc.canvas = canvas;
-pc.g = function() { return g; };
-
-// TODO
-pc.brushReset = function(dimension) {
-  yscale[dimension].brush.clear()(
-    pc.g()
-      .filter(function(p) {
-        return dimension == p;
-      })
-  )
-  return this;
-};
-
-// rescale for height, width and margins
-// TODO currently assumes chart is brushable, and destroys old brushes
-pc.resize = function() {
-  // selection size
-  pc.selection.select("svg")
-    .attr("width", __.width)
-    .attr("height", __.height)
-  pc.svg.attr("transform", "translate(" + __.margin.left + "," + __.margin.top + ")");
-
-  // scales
-  pc.autoscale();
-
-  // axes, destroys old brushes. the current brush state should pass through in the future
-  if (g) pc.createAxes().brushable();
-
-  events.resize.call(this, {width: __.width, height: __.height, margin: __.margin});
-  return this;
-};
-
-// highlight an array of data
-pc.highlight = function(data) {
-  pc.clear("highlight");
-  d3.select(canvas.foreground).classed("faded", true);
-  data.forEach(path_highlight);
-  events.highlight.call(this,data);
-  return this;
-};
-
-// clear highlighting
-pc.unhighlight = function(data) {
-  pc.clear("highlight");
-  d3.select(canvas.foreground).classed("faded", false);
-  return this;
-};
-
-// calculate 2d intersection of line a->b with line c->d
-// points are objects with x and y properties
-pc.intersection =  function(a, b, c, d) {
-  return {
-    x: ((a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x)) / ((a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x)),
-    y: ((a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x)) / ((a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x))
-  };
-};
-
-function is_brushed(p) {
-  return !yscale[p].brush.empty();
-};
-
-// data within extents
-function selected() {
-  var actives = __.dimensions.filter(is_brushed),
-      extents = actives.map(function(p) { return yscale[p].brush.extent(); });
-
-  // test if within range
-  var within = {
-    "number": function(d,p,dimension) {
-      return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1]
-    },
-    "string": function(d,p,dimension) {
-      return extents[dimension][0] <= yscale[p](d[p]) && yscale[p](d[p]) <= extents[dimension][1]
-    }
-  };
-
-  return __.data
-    .filter(function(d) {
-      return actives.every(function(p, dimension) {
-        return within[__.types[p]](d,p,dimension);
-      });
-    });
-};
-
-function position(d) {
-  var v = dragging[d];
-  return v == null ? xscale(d) : v;
-}
-  pc.toString = function() { return "Parallel Coordinates: " + __.dimensions.length + " dimensions (" + d3.keys(__.data[0]).length + " total) , " + __.data.length + " rows"; };
-  
-  pc.version = "0.1.7";
-
-  return pc;
-};
-
-d3.renderQueue = (function(func) {
-  var _queue = [],                  // data to be rendered
-      _rate = 10,                   // number of calls per frame
-      _clear = function() {},       // clearing function
-      _i = 0;                       // current iteration
-
-  var rq = function(data) {
-    if (data) rq.data(data);
-    rq.invalidate();
-    _clear();
-    rq.render();
-  };
-
-  rq.render = function() {
-    _i = 0;
-    var valid = true;
-    rq.invalidate = function() { valid = false; };
-
-    function doFrame() {
-      if (!valid) return false;
-      if (_i > _queue.length) return false;
-      var chunk = _queue.slice(_i,_i+_rate);
-      _i += _rate;
-      chunk.map(func);
-      d3.timer(doFrame);
-    }
-
-    doFrame();
-  };
-
-  rq.data = function(data) {
-    rq.invalidate();
-    _queue = data.slice(0);
-    return rq;
-  };
-
-  rq.rate = function(value) {
-    if (!arguments.length) return _rate;
-    _rate = value;
-    return rq;
-  };
-
-  rq.remaining = function() {
-    return _queue.length - _i;
-  };
-
-  // clear the canvas
-  rq.clear = function(func) {
-    if (!arguments.length) {
-      _clear();
-      return rq;
-    }
-    _clear = func;
-    return rq;
-  };
-
-  rq.invalidate = function() {};
-
-  return rq;
-});
diff --git a/emperor/support_files/js/d3.v3.min.js b/emperor/support_files/js/d3.v3.min.js
deleted file mode 100644
index 3ee7054..0000000
--- a/emperor/support_files/js/d3.v3.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
-d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function i(){}function u(){}function a(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function o(){}function c(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var  [...]
-}function We(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],a=r[0]=Ke(i,u);++t<e;)r[t]=(a+(a=Ke(i=u,u=n[t+1])))/2;return r[t]=a,r}function Qe(n){for(var t,e,r,i,u=[],a=We(n),o=-1,c=n.length-1;++o<c;)t=Ke(n[o],n[o+1]),Math.abs(t)<1e-6?a[o]=a[o+1]=0:(e=a[o]/t,r=a[o+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),a[o]=i*e,a[o+1]=i*r));for(o=-1;++o<=c;)i=(n[Math.min(c,o+1)][0]-n[Math.max(0,o-1)][0])/(6*(1+a[o]*a[o])),u.push([i||0,a[o]*i||0]);return u}function nr(n){return n.length<3?Fe(n):n[0]+Ie(n, [...]
-},add:function(n){return this[ha+n]=!0,n},remove:function(n){return n=ha+n,n in this&&delete this[n]},values:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===ga&&n.call(this,t.substring(1))}}),ua.behavior={},ua.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=a(n,t,t[e]);return n},ua.dispatch=function(){for(var n=new o,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=c(n);return n},o.pro [...]
-}),a=ua.range(n.length).sort(function(n,t){return u[n]-u[t]});return a.filter(function(n,t){return!t||u[n]-u[a[t-1]]>ja}).map(function(t){return n[t]})}),o.forEach(function(n,e){var r=n.length;if(!r)return n.push([-s,-s],[-s,s],[s,s],[s,-s]);if(!(r>2)){var i=t[e],u=n[0],a=n[1],o=i[0],c=i[1],l=u[0],f=u[1],h=a[0],g=a[1],p=Math.abs(h-l),d=g-f;if(Math.abs(d)<ja){var m=f>c?-s:s;n.push([-s,m],[s,m])}else if(ja>p){var v=l>o?-s:s;n.push([v,-s],[v,s])}else{var m=(l-o)*(g-f)>(h-l)*(f-c)?s:-s,y=Mat [...]
-return n?ua.touches(y,n)[0]:ua.mouse(y)}function f(){ua.event.keyCode==32&&(E||(m=null,k[0]-=s[1][0],k[1]-=s[1][1],E=2),l())}function h(){ua.event.keyCode==32&&2==E&&(k[0]+=s[1][0],k[1]+=s[1][1],E=0,l())}function g(){var n=i(),u=!1;v&&(n[0]+=v[0],n[1]+=v[1]),E||(ua.event.altKey?(m||(m=[(s[0][0]+s[1][0])/2,(s[0][1]+s[1][1])/2]),k[0]=s[+(n[0]<m[0])][0],k[1]=s[+(n[1]<m[1])][1]):m=null),w&&p(n,o,0)&&(e(b),u=!0),S&&p(n,c,1)&&(r(b),u=!0),u&&(t(b),x({type:"brush",mode:E?"move":"resize"}))}funct [...]
\ No newline at end of file
diff --git a/emperor/support_files/js/draw.js b/emperor/support_files/js/draw.js
new file mode 100644
index 0000000..17cf88b
--- /dev/null
+++ b/emperor/support_files/js/draw.js
@@ -0,0 +1,174 @@
+/** @module draw */
+define(['underscore', 'three'], function(_, THREE) {
+  /**
+   *
+   * @class EmperorTrajectory
+   *
+   * This class represents the internal logic for a linearly interpolated
+   * tube/trajectory in THREE.js
+   *
+   * [This answer]{@link http://stackoverflow.com/a/18580832/379593} on
+   * StackOverflow helped a lot.
+   * @return {EmperorTrajectory}
+   * @extends THREE.Curve
+   */
+  THREE.EmperorTrajectory = THREE.Curve.create(
+      function(points) {
+        this.points = (points == undefined) ? [] : points;
+      },
+
+      function(t) {
+        var points = this.points;
+        var index = (points.length - 1) * t;
+        var floorIndex = Math.floor(index);
+
+        if (floorIndex == points.length - 1) {
+          return points[floorIndex];
+        }
+
+        var floorPoint = points[floorIndex];
+        var ceilPoint = points[floorIndex + 1];
+
+        return floorPoint.clone().lerp(ceilPoint, index - floorIndex);
+      }
+      );
+
+  /** @private */
+  THREE.EmperorTrajectory.prototype.getUtoTmapping = function(u) {
+    return u;
+  };
+
+
+  /**
+   *
+   * Create a generic THREE.Line object
+   *
+   * @param {float[]} start The x, y and z coordinates of one of the ends
+   * of the line.
+   * @param {float[]} end The x, y and z coordinates of one of the ends
+   * of the line.
+   * @param {integer} color Hexadecimal base that specifies the color of the
+   * line.
+   * @param {float} width The width of the line being drawn.
+   * @param {boolean} transparent Whether the line will be transparent or not.
+   *
+   * @return {THREE.Line}
+   * @function makeLine
+   */
+  function makeLine(start, end, color, width, transparent) {
+    // based on the example described in:
+    // https://github.com/mrdoob/three.js/wiki/Drawing-lines
+    var material, geometry, line;
+
+    // make the material transparent and with full opacity
+    material = new THREE.LineBasicMaterial({color: color, linewidth: width});
+    material.matrixAutoUpdate = true;
+    material.transparent = transparent;
+    material.opacity = 1.0;
+
+    // add the two vertices to the geometry
+    geometry = new THREE.Geometry();
+    geometry.vertices.push(new THREE.Vector3(start[0], start[1], start[2]));
+    geometry.vertices.push(new THREE.Vector3(end[0], end[1], end[2]));
+
+    // the line will contain the two vertices and the described material
+    line = new THREE.Line(geometry, material);
+
+    return line;
+  }
+
+  /**
+   *
+   * Create a THREE object that displays 2D text, this implementation is based
+   * on the answer found
+   * [here]{@link http://stackoverflow.com/a/14106703/379593}
+   *
+   * @param {float[]} position The x, y, and z location of the label.
+   * @param {string} text with the text to be shown on screen.
+   * @param {integer} Color Hexadecimal base that represents the color of
+   * the text.
+   * @param {float} [1] factor An optional scaling factor to determine the size
+   * of the labels.
+   *
+   * @return {THREE.Sprite} Object with the text displaying in it.
+   * @function makeLabel
+   **/
+  function makeLabel(position, text, color, factor) {
+    var canvas = document.createElement('canvas');
+    var size = 512;
+
+    factor = (factor === undefined ? 1 : factor);
+
+    canvas.width = size;
+    canvas.height = size;
+    var context = canvas.getContext('2d');
+    context.fillStyle = '#ffffff';
+    context.textAlign = 'center';
+    context.font = (30 * factor) + 'px Arial';
+    context.fillText(text, size / 2, size / 2);
+
+    var amap = new THREE.Texture(canvas);
+    amap.needsUpdate = true;
+
+    var mat = new THREE.SpriteMaterial({
+        map: amap,
+        transparent: true,
+        color: color
+    });
+
+    var sp = new THREE.Sprite(mat);
+    sp.position.set(position[0], position[1], position[2]);
+
+    // add an extra attribute so we can render this properly when we use
+    // SVGRenderer
+    sp.text = text;
+
+    return sp;
+  }
+
+  /**
+   *
+   * Format an SVG string with labels and colors.
+   *
+   * @param {string[]} labels The names for the label.
+   * @param {integer[]} colors The colors for each label.
+   *
+   * @return {string} SVG string with the labels and colors values formated as
+   * a legend.
+   * @function formatSVGLegend
+   */
+  function formatSVGLegend(labels, colors) {
+    var labels_svg = '', pos_y = 1, increment = 40, max_len = 0, rect_width,
+    font_size = 12;
+
+    for (var i = 0; i < labels.length; i++) {
+      // add the rectangle with the corresponding color
+      labels_svg += '<rect height="27" width="27" y="' + pos_y +
+        '" x="5" style="stroke-width:1;stroke:rgb(0,0,0)" fill="' +
+        colors[i] + '"/>';
+
+      // add the name of the category
+      labels_svg += '<text xml:space="preserve" y="' + (pos_y + 20) +
+        '" x="40" font-size="' + font_size +
+        '" stroke-width="0" stroke="#000000" fill="#000000">' + labels[i] +
+        '</text>';
+
+      pos_y += increment;
+    }
+
+    // get the name with the maximum number of characters and get the length
+    max_len = _.max(labels, function(a) {return a.length}).length;
+
+      // duplicate the size of the rectangle to make sure it fits the labels
+      rect_width = font_size * max_len * 2;
+
+    labels_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' +
+      rect_width + '" height="' + (pos_y - 10) + '"><g>' + labels_svg +
+      '</g></svg>';
+
+    return labels_svg;
+  }
+
+  return {'formatSVGLegend': formatSVGLegend, 'makeLine': makeLine,
+          'makeLabel': makeLabel};
+});
diff --git a/emperor/support_files/js/jquery-1.7.1.min.js b/emperor/support_files/js/jquery-1.7.1.min.js
deleted file mode 100644
index 198b3ff..0000000
--- a/emperor/support_files/js/jquery-1.7.1.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v1.7.1 jquery.com | jquery.org/license */
-(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement( [...]
-f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]| [...]
-{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replac [...]
\ No newline at end of file
diff --git a/emperor/support_files/js/jquery-ui-1.8.17.custom.min.js b/emperor/support_files/js/jquery-ui-1.8.17.custom.min.js
deleted file mode 100755
index 991cb8d..0000000
--- a/emperor/support_files/js/jquery-ui-1.8.17.custom.min.js
+++ /dev/null
@@ -1,356 +0,0 @@
-/*!
- * jQuery UI 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI
- */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a. [...]
- * jQuery UI Widget 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Widget
- */(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}});return d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.e [...]
- * jQuery UI Mouse 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Mouse
- *
- * Depends:
- *	jquery.ui.widget.js
- */(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent")){a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation();return!1}}),this.started=!1},_mouseDestroy:funct [...]
- * jQuery UI Position 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Position
- */(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0 [...]
- * jQuery UI Draggable 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Draggables
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.mouse.js
- *	jquery.ui.widget.js
- */(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test [...]
- * jQuery UI Droppable 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Droppables
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- *	jquery.ui.mouse.js
- *	jquery.ui.draggable.js
- */(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager. [...]
- * jQuery UI Resizable 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizables
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.mouse.js
- *	jquery.ui.widget.js
- */(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.elemen [...]
- * jQuery UI Selectable 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectables
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.mouse.js
- *	jquery.ui.widget.js
- */(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),s [...]
- * jQuery UI Sortable 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Sortables
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.mouse.js
- *	jquery.ui.widget.js
- */(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("u [...]
- * jQuery UI Accordion 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- */(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").chi [...]
- * jQuery UI Autocomplete 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- *	jquery.ui.position.js
- */(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!b.options.disabled&&!b.element.propAttr(" [...]
- * jQuery UI Button 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- */(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function( [...]
- * jQuery UI Dialog 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- *  jquery.ui.button.js
- *	jquery.ui.draggable.js
- *	jquery.ui.mouse.js
- *	jquery.ui.position.js
- *	jquery.ui.resizable.js
- */(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},f=a.attrFn||{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0,click:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWi [...]
- * jQuery UI Slider 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.mouse.js
- *	jquery.ui.widget.js
- */(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff [...]
- * jQuery UI Tabs 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- */(function(a,b){function f(){return++d}function e(){return++c}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="sel [...]
- * jQuery UI Datepicker 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker
- *
- * Depends:
- *	jquery.ui.core.js
- */(function($,undefined){function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);!c.length||c.removeClass("ui-state-hover ui-d [...]
-._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" "+">";for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k [...]
- * jQuery UI Progressbar 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar
- *
- * Depends:
- *   jquery.ui.core.js
- *   jquery.ui.widget.js
- */(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.re [...]
- * jQuery UI Effects 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/
- */jQuery.effects||function(a,b){function l(b){if(!b||typeof b=="number"||a.fx.speeds[b])return!0;if(typeof b=="string"&&!a.effects[b])return!0;return!1}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete;return[b,c,d,e]}function j(a [...]
- * jQuery UI Effects Blind 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Blind
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(), [...]
- * jQuery UI Effects Bounce 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Bounce
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight({marg [...]
- * jQuery UI Effects Clip 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Clip
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i. [...]
- * jQuery UI Effects Drop 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Drop
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight({margin:!0})/2:c.outerWidth({margin:!0})/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j [...]
- * jQuery UI Effects Explode 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Explode
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var [...]
- * jQuery UI Effects Fade 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Fade
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);/*
- * jQuery UI Effects Fold 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Fold
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m& [...]
- * jQuery UI Effects Highlight 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Highlight
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e==" [...]
- * jQuery UI Effects Pulsate 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Pulsate
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show");times=(b.options.times||5)*2-1,duration=b.duration?b.duration/2:a.fx.speeds._default/2,isVisible=c.is(":visible"),animateTo=0,isVisible||(c.css("opacity",0).show(),animateTo=1),(d=="hide"&&isVisible||d=="show"&&!isVisible)&&times--;for(var e=0;e<times;e++)c.animate({opacity:animateTo},duration,b.options.easing),animateTo=(animateTo+1)%2;c.animate({opaci [...]
- * jQuery UI Effects Scale 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Scale
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.optio [...]
- * jQuery UI Effects Shake 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Shake
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+ [...]
- * jQuery UI Effects Slide 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Slide
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight({margin:!0}):c.outerWidth({margin:!0}));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:- [...]
- * jQuery UI Effects Transfer 1.8.17
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Transfer
- *
- * Depends:
- *	jquery.effects.core.js
- */(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0 [...]
\ No newline at end of file
diff --git a/emperor/support_files/js/jquery.colorPicker.js b/emperor/support_files/js/jquery.colorPicker.js
deleted file mode 100755
index 02ba9b0..0000000
--- a/emperor/support_files/js/jquery.colorPicker.js
+++ /dev/null
@@ -1,328 +0,0 @@
-/**
- * Really Simple Color Picker in jQuery
- *
- * Licensed under the MIT (MIT-LICENSE.txt) licenses.
- *
- * Copyright (c) 2008-2012
- * Lakshan Perera (www.laktek.com) & Daniel Lacy (daniellacy.com)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-(function ($) {
-    /**
-     * Create a couple private variables.
-    **/
-    var selectorOwner,
-        activePalette,
-        cItterate       = 0,
-        templates       = {
-            control : $('<div class="colorPicker-picker"> </div>'),
-            palette : $('<div id="colorPicker_palette" class="colorPicker-palette" />'),
-            swatch  : $('<div class="colorPicker-swatch"> </div>'),
-            hexLabel: $('<label for="colorPicker_hex">Hex</label>'),
-            hexField: $('<input type="text" id="colorPicker_hex" />')
-        },
-        transparent     = "transparent",
-        lastColor;
-
-    /**
-     * Create our colorPicker function
-    **/
-    $.fn.colorPicker = function (options) {
-
-        return this.each(function () {
-            // Setup time. Clone new elements from our templates, set some IDs, make shortcuts, jazzercise.
-            var element      = $(this),
-                opts         = $.extend({}, $.fn.colorPicker.defaults, options),
-                defaultColor = $.fn.colorPicker.toHex(
-                        (element.val().length > 0) ? element.val() : opts.pickerDefault
-                    ),
-                newControl   = templates.control.clone(),
-                newPalette   = templates.palette.clone().attr('id', 'colorPicker_palette-' + cItterate),
-                newHexLabel  = templates.hexLabel.clone(),
-                newHexField  = templates.hexField.clone(),
-                paletteId    = newPalette[0].id,
-                swatch;
-
-
-            /**
-             * Build a color palette.
-            **/
-            $.each(opts.colors, function (i) {
-                swatch = templates.swatch.clone();
-
-                if (opts.colors[i] === transparent) {
-                    swatch.addClass(transparent).text('X');
-                    $.fn.colorPicker.bindPalette(newHexField, swatch, transparent);
-                } else {
-                    swatch.css("background-color", "#" + this);
-                    $.fn.colorPicker.bindPalette(newHexField, swatch);
-                }
-                swatch.appendTo(newPalette);
-            });
-
-            newHexLabel.attr('for', 'colorPicker_hex-' + cItterate);
-
-            newHexField.attr({
-                'id'    : 'colorPicker_hex-' + cItterate,
-                'value' : defaultColor
-            });
-
-            newHexField.bind("keydown", function (event) {
-                if (event.keyCode === 13) {
-                    var hexColor = $.fn.colorPicker.toHex($(this).val());
-                    $.fn.colorPicker.changeColor(hexColor ? hexColor : element.val());
-                }
-                if (event.keyCode === 27) {
-                    $.fn.colorPicker.hidePalette();
-                }
-            });
-
-            newHexField.bind("keyup", function (event) {
-              var hexColor = $.fn.colorPicker.toHex($(event.target).val());
-              $.fn.colorPicker.previewColor(hexColor ? hexColor : element.val());
-            });
-
-            $('<div class="colorPicker_hexWrap" />').append(newHexLabel).appendTo(newPalette);
-
-            newPalette.find('.colorPicker_hexWrap').append(newHexField);
-
-            $("body").append(newPalette);
-
-            newPalette.hide();
-
-
-            /**
-             * Build replacement interface for original color input.
-            **/
-            newControl.css("background-color", defaultColor);
-
-            newControl.bind("click", function () {
-                $.fn.colorPicker.togglePalette($('#' + paletteId), $(this));
-            });
-
-            if( options && options.onColorChange ) {
-              newControl.data('onColorChange', options.onColorChange);
-            } else {
-              newControl.data('onColorChange', function() {} );
-            }
-            element.after(newControl);
-
-            element.bind("change", function () {
-                element.next(".colorPicker-picker").css(
-                    "background-color", $.fn.colorPicker.toHex($(this).val())
-                );
-            });
-
-            // Hide the original input.
-            element.val(defaultColor).hide();
-
-            cItterate++;
-        });
-    };
-
-    /**
-     * Extend colorPicker with... all our functionality.
-    **/
-    $.extend(true, $.fn.colorPicker, {
-        /**
-         * Return a Hex color, convert an RGB value and return Hex, or return false.
-         *
-         * Inspired by http://code.google.com/p/jquery-color-utils
-        **/
-        toHex : function (color) {
-            // If we have a standard or shorthand Hex color, return that value.
-            if (color.match(/[0-9A-F]{6}|[0-9A-F]{3}$/i)) {
-                return (color.charAt(0) === "#") ? color : ("#" + color);
-
-            // Alternatively, check for RGB color, then convert and return it as Hex.
-            } else if (color.match(/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/)) {
-                var c = ([parseInt(RegExp.$1, 10), parseInt(RegExp.$2, 10), parseInt(RegExp.$3, 10)]),
-                    pad = function (str) {
-                        if (str.length < 2) {
-                            for (var i = 0, len = 2 - str.length; i < len; i++) {
-                                str = '0' + str;
-                            }
-                        }
-
-                        return str;
-                    };
-
-                if (c.length === 3) {
-                    var r = pad(c[0].toString(16)),
-                        g = pad(c[1].toString(16)),
-                        b = pad(c[2].toString(16));
-
-                    return '#' + r + g + b;
-                }
-
-            // Otherwise we wont do anything.
-            } else {
-                return false;
-
-            }
-        },
-
-        /**
-         * Check whether user clicked on the selector or owner.
-        **/
-        checkMouse : function (event, paletteId) {
-            var selector = activePalette,
-                selectorParent = $(event.target).parents("#" + selector.attr('id')).length;
-
-            if (event.target === $(selector)[0] || event.target === selectorOwner[0] || selectorParent > 0) {
-                return;
-            }
-
-            $.fn.colorPicker.hidePalette();
-        },
-
-        /**
-         * Hide the color palette modal.
-        **/
-        hidePalette : function () {
-            $(document).unbind("mousedown", $.fn.colorPicker.checkMouse);
-
-            $('.colorPicker-palette').hide();
-        },
-
-        /**
-         * Show the color palette modal.
-        **/
-        showPalette : function (palette) {
-            var hexColor = selectorOwner.prev("input").val();
-
-            palette.css({
-                top: selectorOwner.offset().top + (selectorOwner.outerHeight()),
-                left: selectorOwner.offset().left
-            });
-
-            $("#color_value").val(hexColor);
-
-            palette.show();
-
-            $(document).bind("mousedown", $.fn.colorPicker.checkMouse);
-        },
-
-        /**
-         * Toggle visibility of the colorPicker palette.
-        **/
-        togglePalette : function (palette, origin) {
-            // selectorOwner is the clicked .colorPicker-picker.
-            if (origin) {
-                selectorOwner = origin;
-            }
-
-            activePalette = palette;
-
-            if (activePalette.is(':visible')) {
-                $.fn.colorPicker.hidePalette();
-
-            } else {
-                $.fn.colorPicker.showPalette(palette);
-
-            }
-        },
-
-        /**
-         * Update the input with a newly selected color.
-        **/
-        changeColor : function (value) {
-            selectorOwner.css("background-color", value);
-            selectorOwner.prev("input").val(value).change();
-
-            $.fn.colorPicker.hidePalette();
-
-            selectorOwner.data('onColorChange').call(selectorOwner, $(selectorOwner).prev("input").attr("id"), value);
-        },
-
-
-        /**
-         * Preview the input with a newly selected color.
-        **/
-        previewColor : function (value) {
-            selectorOwner.css("background-color", value);
-        },
-
-        /**
-         * Bind events to the color palette swatches.
-        */
-        bindPalette : function (paletteInput, element, color) {
-            color = color ? color : $.fn.colorPicker.toHex(element.css("background-color"));
-
-            element.bind({
-                click : function (ev) {
-                    lastColor = color;
-
-                    $.fn.colorPicker.changeColor(color);
-                },
-                mouseover : function (ev) {
-                    lastColor = paletteInput.val();
-
-                    $(this).css("border-color", "#598FEF");
-
-                    paletteInput.val(color);
-
-                    $.fn.colorPicker.previewColor(color);
-                },
-                mouseout : function (ev) {
-                    $(this).css("border-color", "#000");
-
-                    paletteInput.val(selectorOwner.css("background-color"));
-
-                    paletteInput.val(lastColor);
-
-                    $.fn.colorPicker.previewColor(lastColor);
-                }
-            });
-        }
-    });
-
-    /**
-     * Default colorPicker options.
-     *
-     * These are publibly available for global modification using a setting such as:
-     *
-     * $.fn.colorPicker.defaults.colors = ['151337', '111111']
-     *
-     * They can also be applied on a per-bound element basis like so:
-     *
-     * $('#element1').colorPicker({pickerDefault: 'efefef', transparency: true});
-     * $('#element2').colorPicker({pickerDefault: '333333', colors: ['333333', '111111']});
-     *
-    **/
-    $.fn.colorPicker.defaults = {
-        // colorPicker default selected color.
-        pickerDefault : "FFFFFF",
-
-        // Default color set.
-        colors : [
-            '000000', '993300', '333300', '000080', '333399', '333333', '800000', 'FF6600',
-            '808000', '008000', '008080', '0000FF', '666699', '808080', 'FF0000', 'FF9900',
-            '99CC00', '339966', '33CCCC', '3366FF', '800080', '999999', 'FF00FF', 'FFCC00',
-            'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0', 'FF99CC', 'FFCC99',
-            'FFFF99', 'CCFFFF', '99CCFF', 'FFFFFF'
-        ],
-
-        // If we want to simply add more colors to the default set, use addColors.
-        addColors : []
-    };
-
-})(jQuery);
diff --git a/emperor/support_files/js/js/AudioObject.js b/emperor/support_files/js/js/AudioObject.js
deleted file mode 100644
index f631329..0000000
--- a/emperor/support_files/js/js/AudioObject.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * AudioObject
- *
- *	- 3d spatialized sound with Doppler-shift effect
- *
- *	- uses Audio API (currently supported in WebKit-based browsers)
- *		https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
- *
- *	- based on Doppler effect demo from Chromium
- * 		http://chromium.googlecode.com/svn/trunk/samples/audio/doppler.html
- *
- * - parameters
- *
- *		- listener
- *			dopplerFactor	// A constant used to determine the amount of pitch shift to use when rendering a doppler effect.
- *			speedOfSound	// The speed of sound used for calculating doppler shift. The default value is 343.3 meters / second.
- *
- *		- panner
- *			refDistance		// A reference distance for reducing volume as source move further from the listener.
- *			maxDistance		// The maximum distance between source and listener, after which the volume will not be reduced any further.
- *			rolloffFactor	// Describes how quickly the volume is reduced as source moves away from listener.
- * 			coneInnerAngle	// An angle inside of which there will be no volume reduction.
- *			coneOuterAngle 	// An angle outside of which the volume will be reduced to a constant value of coneOuterGain.
- *			coneOuterGain	// Amount of volume reduction outside of the coneOuterAngle.
- */
-
-THREE.AudioObject = function ( url, volume, playbackRate, loop ) {
-
-	THREE.Object3D.call( this );
-
-	if ( playbackRate === undefined ) playbackRate = 1;
-	if ( volume === undefined ) volume = 1;
-	if ( loop === undefined ) loop = true;
-
-	if ( ! this.context ) {
-
-		try {
-
-			this.context = new webkitAudioContext();
-
-		} catch( error ) {
-
-			console.warn( "THREE.AudioObject: webkitAudioContext not found" );
-			return this;
-
-		}
-
-	}
-
-	this.directionalSource = false;
-
-	this.listener = this.context.listener;
-	this.panner = this.context.createPanner();
-	this.source = this.context.createBufferSource();
-
-	this.masterGainNode = this.context.createGainNode();
-	this.dryGainNode = this.context.createGainNode();
-
-	// Setup initial gains
-
-	this.masterGainNode.gain.value = volume;
-	this.dryGainNode.gain.value = 3.0;
-
-	// Connect dry mix
-
-	this.source.connect( this.panner );
-	this.panner.connect( this.dryGainNode );
-	this.dryGainNode.connect( this.masterGainNode );
-
-	// Connect master gain
-
-	this.masterGainNode.connect( this.context.destination );
-
-	// Set source parameters and load sound
-
-	this.source.playbackRate.value = playbackRate;
-	this.source.loop = loop;
-
-	loadBufferAndPlay( url );
-
-	// private properties
-
-	var soundPosition = new THREE.Vector3(),
-	cameraPosition = new THREE.Vector3(),
-	oldSoundPosition = new THREE.Vector3(),
-	oldCameraPosition = new THREE.Vector3(),
-
-	soundDelta = new THREE.Vector3(),
-	cameraDelta = new THREE.Vector3(),
-
-	soundFront = new THREE.Vector3(),
-	cameraFront = new THREE.Vector3(),
-	soundUp = new THREE.Vector3(),
-	cameraUp = new THREE.Vector3();
-
-	var _this = this;
-
-	// API
-
-	this.setVolume = function ( volume ) {
-
-		this.masterGainNode.gain.value = volume;
-
-	};
-
-	this.update = function ( camera ) {
-
-		oldSoundPosition.copy( soundPosition );
-		oldCameraPosition.copy( cameraPosition );
-
-		soundPosition.copy( this.matrixWorld.getPosition() );
-		cameraPosition.copy( camera.matrixWorld.getPosition() );
-
-		soundDelta.sub( soundPosition, oldSoundPosition );
-		cameraDelta.sub( cameraPosition, oldCameraPosition );
-
-		cameraUp.copy( camera.up );
-
-		cameraFront.set( 0, 0, -1 );
-		camera.matrixWorld.rotateAxis( cameraFront );
-		cameraFront.normalize();
-
-		this.listener.setPosition( cameraPosition.x, cameraPosition.y, cameraPosition.z );
-		this.listener.setVelocity( cameraDelta.x, cameraDelta.y, cameraDelta.z );
-		this.listener.setOrientation( cameraFront.x, cameraFront.y, cameraFront.z, cameraUp.x, cameraUp.y, cameraUp.z );
-
-		this.panner.setPosition( soundPosition.x, soundPosition.y, soundPosition.z );
-		this.panner.setVelocity( soundDelta.x, soundDelta.y, soundDelta.z );
-
-		if ( this.directionalSource ) {
-
-			soundFront.set( 0, 0, -1 );
-			this.matrixWorld.rotateAxis( soundFront );
-			soundFront.normalize();
-
-			soundUp.copy( this.up );
-			this.panner.setOrientation( soundFront.x, soundFront.y, soundFront.z, soundUp.x, soundUp.y, soundUp.z );
-
-		}
-
-
-	};
-
-	function loadBufferAndPlay( url ) {
-
-		// Load asynchronously
-
-		var request = new XMLHttpRequest();
-		request.open( "GET", url, true );
-		request.responseType = "arraybuffer";
-
-		request.onload = function() {
-
-			_this.source.buffer = _this.context.createBuffer( request.response, true );
-			_this.source.noteOn( 0 );
-
-		}
-
-		request.send();
-
-	}
-
-};
-
-THREE.AudioObject.prototype = new THREE.Object3D();
-THREE.AudioObject.prototype.constructor = THREE.AudioObject;
-
-THREE.AudioObject.prototype.context = null;
-THREE.AudioObject.prototype.type = null;
-
diff --git a/emperor/support_files/js/js/Car.js b/emperor/support_files/js/js/Car.js
deleted file mode 100644
index 1853210..0000000
--- a/emperor/support_files/js/js/Car.js
+++ /dev/null
@@ -1,364 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Car = function () {
-
-	var scope = this;
-
-	// car geometry manual parameters
-
-	this.modelScale = 1;
-
-	this.backWheelOffset = 2;
-
-	this.autoWheelGeometry = true;
-
-	// car geometry parameters automatically set from wheel mesh
-	// 	- assumes wheel mesh is front left wheel in proper global
-	//    position with respect to body mesh
-	//	- other wheels are mirrored against car root
-	//	- if necessary back wheels can be offset manually
-
-	this.wheelOffset = new THREE.Vector3();
-
-	this.wheelDiameter = 1;
-
-	// car "feel" parameters
-
-	this.MAX_SPEED = 2200;
-	this.MAX_REVERSE_SPEED = -1500;
-
-	this.MAX_WHEEL_ROTATION = 0.6;
-
-	this.FRONT_ACCELERATION = 1250;
-	this.BACK_ACCELERATION = 1500;
-
-	this.WHEEL_ANGULAR_ACCELERATION = 1.5;
-
-	this.FRONT_DECCELERATION = 750;
-	this.WHEEL_ANGULAR_DECCELERATION = 1.0;
-
-	this.STEERING_RADIUS_RATIO = 0.0023;
-
-	this.MAX_TILT_SIDES = 0.05;
-	this.MAX_TILT_FRONTBACK = 0.015;
-
-	// internal control variables
-
-	this.speed = 0;
-	this.acceleration = 0;
-
-	this.wheelOrientation = 0;
-	this.carOrientation = 0;
-
-	// car rigging
-
-	this.root = new THREE.Object3D();
-
-	this.frontLeftWheelRoot = new THREE.Object3D();
-	this.frontRightWheelRoot = new THREE.Object3D();
-
-	this.bodyMesh = null;
-
-	this.frontLeftWheelMesh = null;
-	this.frontRightWheelMesh = null;
-
-	this.backLeftWheelMesh = null;
-	this.backRightWheelMesh = null;
-
-	this.bodyGeometry = null;
-	this.wheelGeometry = null;
-
-	// internal helper variables
-
-	this.loaded = false;
-
-	this.meshes = [];
-
-	// API
-
-	this.enableShadows = function ( enable ) {
-
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
-
-			this.meshes[ i ].castShadow = enable;
-			this.meshes[ i ].receiveShadow = enable;
-
-		}
-
-	};
-
-	this.setVisible = function ( enable ) {
-
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
-
-			this.meshes[ i ].visible = enable;
-			this.meshes[ i ].visible = enable;
-
-		}
-
-	};
-
-	this.loadPartsJSON = function ( bodyURL, wheelURL ) {
-
-		var loader = new THREE.JSONLoader();
-
-		loader.load( bodyURL, function( geometry ) { createBody( geometry ) } );
-		loader.load( wheelURL, function( geometry ) { createWheels( geometry ) } );
-
-	};
-
-	this.loadPartsBinary = function ( bodyURL, wheelURL ) {
-
-		var loader = new THREE.BinaryLoader();
-
-		loader.load( bodyURL, function( geometry ) { createBody( geometry ) } );
-		loader.load( wheelURL, function( geometry ) { createWheels( geometry ) } );
-
-	};
-
-	this.updateCarModel = function ( delta, controls ) {
-
-		// speed and wheels based on controls
-
-		if ( controls.moveForward ) {
-
-			this.speed = THREE.Math.clamp( this.speed + delta * this.FRONT_ACCELERATION, this.MAX_REVERSE_SPEED, this.MAX_SPEED );
-			this.acceleration = THREE.Math.clamp( this.acceleration + delta, -1, 1 );
-
-		}
-
-		if ( controls.moveBackward ) {
-
-
-			this.speed = THREE.Math.clamp( this.speed - delta * this.BACK_ACCELERATION, this.MAX_REVERSE_SPEED, this.MAX_SPEED );
-			this.acceleration = THREE.Math.clamp( this.acceleration - delta, -1, 1 );
-
-		}
-
-		if ( controls.moveLeft ) {
-
-			this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation + delta * this.WHEEL_ANGULAR_ACCELERATION, - this.MAX_WHEEL_ROTATION, this.MAX_WHEEL_ROTATION );
-
-		}
-
-		if ( controls.moveRight ) {
-
-			this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation - delta * this.WHEEL_ANGULAR_ACCELERATION, - this.MAX_WHEEL_ROTATION, this.MAX_WHEEL_ROTATION );
-
-		}
-
-		// speed decay
-
-		if ( ! ( controls.moveForward || controls.moveBackward ) ) {
-
-			if ( this.speed > 0 ) {
-
-				var k = exponentialEaseOut( this.speed / this.MAX_SPEED );
-
-				this.speed = THREE.Math.clamp( this.speed - k * delta * this.FRONT_DECCELERATION, 0, this.MAX_SPEED );
-				this.acceleration = THREE.Math.clamp( this.acceleration - k * delta, 0, 1 );
-
-			} else {
-
-				var k = exponentialEaseOut( this.speed / this.MAX_REVERSE_SPEED );
-
-				this.speed = THREE.Math.clamp( this.speed + k * delta * this.BACK_ACCELERATION, this.MAX_REVERSE_SPEED, 0 );
-				this.acceleration = THREE.Math.clamp( this.acceleration + k * delta, -1, 0 );
-
-			}
-
-
-		}
-
-		// steering decay
-
-		if ( ! ( controls.moveLeft || controls.moveRight ) ) {
-
-			if ( this.wheelOrientation > 0 ) {
-
-				this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation - delta * this.WHEEL_ANGULAR_DECCELERATION, 0, this.MAX_WHEEL_ROTATION );
-
-			} else {
-
-				this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation + delta * this.WHEEL_ANGULAR_DECCELERATION, - this.MAX_WHEEL_ROTATION, 0 );
-
-			}
-
-		}
-
-		// car update
-
-		var forwardDelta = this.speed * delta;
-
-		this.carOrientation += ( forwardDelta * this.STEERING_RADIUS_RATIO )* this.wheelOrientation;
-
-		// displacement
-
-		this.root.position.x += Math.sin( this.carOrientation ) * forwardDelta;
-		this.root.position.z += Math.cos( this.carOrientation ) * forwardDelta;
-
-		// steering
-
-		this.root.rotation.y = this.carOrientation;
-
-		// tilt
-
-		if ( this.loaded ) {
-
-			this.bodyMesh.rotation.z = this.MAX_TILT_SIDES * this.wheelOrientation * ( this.speed / this.MAX_SPEED );
-			this.bodyMesh.rotation.x = - this.MAX_TILT_FRONTBACK * this.acceleration;
-
-		}
-
-		// wheels rolling
-
-		var angularSpeedRatio = 1 / ( this.modelScale * ( this.wheelDiameter / 2 ) );
-
-		var wheelDelta = forwardDelta * angularSpeedRatio;
-
-		if ( this.loaded ) {
-
-			this.frontLeftWheelMesh.rotation.x += wheelDelta;
-			this.frontRightWheelMesh.rotation.x += wheelDelta;
-			this.backLeftWheelMesh.rotation.x += wheelDelta;
-			this.backRightWheelMesh.rotation.x += wheelDelta;
-
-		}
-
-		// front wheels steering
-
-		this.frontLeftWheelRoot.rotation.y = this.wheelOrientation;
-		this.frontRightWheelRoot.rotation.y = this.wheelOrientation;
-
-	};
-
-	// internal helper methods
-
-	function createBody ( geometry ) {
-
-		scope.bodyGeometry = geometry;
-
-		createCar();
-
-	};
-
-	function createWheels ( geometry ) {
-
-		scope.wheelGeometry = geometry;
-
-		createCar();
-
-	};
-
-	function createCar () {
-
-		if ( scope.bodyGeometry && scope.wheelGeometry ) {
-
-			// compute wheel geometry parameters
-
-			if ( scope.autoWheelGeometry ) {
-
-				scope.wheelGeometry.computeBoundingBox();
-
-				var bb = scope.wheelGeometry.boundingBox;
-
-				scope.wheelOffset.add( bb.min, bb.max );
-				scope.wheelOffset.multiplyScalar( 0.5 );
-
-				scope.wheelDiameter = bb.max.y - bb.min.y;
-
-				THREE.GeometryUtils.center( scope.wheelGeometry );
-
-			}
-
-			// rig the car
-
-			var s = scope.modelScale,
-				delta = new THREE.Vector3(),
-				faceMaterial = new THREE.MeshFaceMaterial();
-
-			// body
-
-			scope.bodyMesh = new THREE.Mesh( scope.bodyGeometry, faceMaterial );
-			scope.bodyMesh.scale.set( s, s, s );
-
-			scope.root.add( scope.bodyMesh );
-
-			// front left wheel
-
-			delta.multiply( scope.wheelOffset, new THREE.Vector3( s, s, s ) );
-
-			scope.frontLeftWheelRoot.position.addSelf( delta );
-
-			scope.frontLeftWheelMesh = new THREE.Mesh( scope.wheelGeometry, faceMaterial );
-			scope.frontLeftWheelMesh.scale.set( s, s, s );
-
-			scope.frontLeftWheelRoot.add( scope.frontLeftWheelMesh );
-			scope.root.add( scope.frontLeftWheelRoot );
-
-			// front right wheel
-
-			delta.multiply( scope.wheelOffset, new THREE.Vector3( -s, s, s ) );
-
-			scope.frontRightWheelRoot.position.addSelf( delta );
-
-			scope.frontRightWheelMesh = new THREE.Mesh( scope.wheelGeometry, faceMaterial );
-
-			scope.frontRightWheelMesh.scale.set( s, s, s );
-			scope.frontRightWheelMesh.rotation.z = Math.PI;
-
-			scope.frontRightWheelRoot.add( scope.frontRightWheelMesh );
-			scope.root.add( scope.frontRightWheelRoot );
-
-			// back left wheel
-
-			delta.multiply( scope.wheelOffset, new THREE.Vector3( s, s, -s ) );
-			delta.z -= scope.backWheelOffset;
-
-			scope.backLeftWheelMesh = new THREE.Mesh( scope.wheelGeometry, faceMaterial );
-
-			scope.backLeftWheelMesh.position.addSelf( delta );
-			scope.backLeftWheelMesh.scale.set( s, s, s );
-
-			scope.root.add( scope.backLeftWheelMesh );
-
-			// back right wheel
-
-			delta.multiply( scope.wheelOffset, new THREE.Vector3( -s, s, -s ) );
-			delta.z -= scope.backWheelOffset;
-
-			scope.backRightWheelMesh = new THREE.Mesh( scope.wheelGeometry, faceMaterial );
-
-			scope.backRightWheelMesh.position.addSelf( delta );
-			scope.backRightWheelMesh.scale.set( s, s, s );
-			scope.backRightWheelMesh.rotation.z = Math.PI;
-
-			scope.root.add( scope.backRightWheelMesh );
-
-			// cache meshes
-
-			scope.meshes = [ scope.bodyMesh, scope.frontLeftWheelMesh, scope.frontRightWheelMesh, scope.backLeftWheelMesh, scope.backRightWheelMesh ];
-
-			// callback
-
-			scope.loaded = true;
-
-			if ( scope.callback ) {
-
-				scope.callback( scope );
-
-			}
-
-		}
-
-	};
-
-	function quadraticEaseOut( k ) { return - k * ( k - 2 ); }
-	function cubicEaseOut( k ) { return --k * k * k + 1; }
-	function circularEaseOut( k ) { return Math.sqrt( 1 - --k * k ); }
-	function sinusoidalEaseOut( k ) { return Math.sin( k * Math.PI / 2 ); }
-	function exponentialEaseOut( k ) { return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1; }
-
-};
diff --git a/emperor/support_files/js/js/DAT.GUI.min.js b/emperor/support_files/js/js/DAT.GUI.min.js
deleted file mode 100644
index 8ed2120..0000000
--- a/emperor/support_files/js/js/DAT.GUI.min.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * dat.gui Javascript Controller Library
- * http://dataarts.github.com/dat.gui
- *
- * Copyright 2011 Data Arts Team, Google Creative Lab
- *
- * 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
- */
-var DAT=DAT||{};
-DAT.GUI=function(a){a==void 0&&(a={});var b=!1;a.height==void 0?a.height=300:b=!0;var d=[],c=[],i=!0,f,h,j=this,g=!0,e=280;if(a.width!=void 0)e=a.width;var q=!1,k,p,n=0,r;this.domElement=document.createElement("div");this.domElement.setAttribute("class","guidat");this.domElement.style.width=e+"px";var l=a.height,m=document.createElement("div");m.setAttribute("class","guidat-controllers");m.style.height=l+"px";m.addEventListener("DOMMouseScroll",function(a){var b=this.scrollTop;a.wheelDel [...]
-a.detail&&(b+=a.detail);a.preventDefault&&a.preventDefault();a.returnValue=!1;m.scrollTop=b},!1);var o=document.createElement("a");o.setAttribute("class","guidat-toggle");o.setAttribute("href","#");o.innerHTML=g?"Close Controls":"Open Controls";var t=!1,C=0,x=0,u=!1,v,y,w,z,D=function(a){y=v;z=w;v=a.pageY;w=a.pageX;a=v-y;if(!g)if(a>0)g=!0,l=k=1,o.innerHTML=p||"Close Controls";else return;var b=z-w;if(a>0&&l>h){var d=DAT.GUI.map(l,h,h+100,1,0);a*=d}t=!0;C+=a;k+=a;l+=a;m.style.height=k+"px [...]
-b;e=DAT.GUI.constrain(e,240,500);j.domElement.style.width=e+"px";A()};o.addEventListener("mousedown",function(a){y=v=a.pageY;z=w=a.pageX;u=!0;a.preventDefault();C=x=0;document.addEventListener("mousemove",D,!1);return!1},!1);o.addEventListener("click",function(a){a.preventDefault();return!1},!1);document.addEventListener("mouseup",function(a){u&&!t&&j.toggle();if(u&&t)if(x==0&&B(),k>h)clearTimeout(r),k=n=h,s();else if(m.children.length>=1){var b=m.children[0].offsetHeight;clearTimeout(r) [...]
-b)*b-1;n<=0?(j.close(),k=b*2):(k=n,s())}document.removeEventListener("mousemove",D,!1);a.preventDefault();return u=t=!1},!1);this.domElement.appendChild(m);this.domElement.appendChild(o);if(a.domElement)a.domElement.appendChild(this.domElement);else if(DAT.GUI.autoPlace){if(DAT.GUI.autoPlaceContainer==null)DAT.GUI.autoPlaceContainer=document.createElement("div"),DAT.GUI.autoPlaceContainer.setAttribute("id","guidat"),document.body.appendChild(DAT.GUI.autoPlaceContainer);DAT.GUI.autoPlaceC [...]
-1E3/60;var E=function(){f=setInterval(function(){j.listen()},this.autoListenIntervalTime)};this.__defineSetter__("autoListen",function(a){(i=a)?c.length>0&&E():clearInterval(f)});this.__defineGetter__("autoListen",function(){return i});this.listenTo=function(a){c.length==0&&E();c.push(a)};this.unlistenTo=function(a){for(var b=0;b<c.length;b++)c[b]==a&&c.splice(b,1);c.length<=0&&clearInterval(f)};this.listen=function(a){var a=a||c,b;for(b in a)a[b].updateDisplay()};this.listenAll=function [...]
-this.autoListen=!0;var F=function(a,b){function d(){return a.apply(this,b)}d.prototype=a.prototype;return new d};this.add=function(){if(arguments.length==1){var a=[],c;for(c in arguments[0])a.push(j.add(arguments[0],c));return a}a=arguments[0];c=arguments[1];a:for(var e in d)if(d[e].object==a&&d[e].propertyName==c)break a;e=a[c];e==void 0&&a.get&&(e=a.get(c));if(e==void 0)DAT.GUI.error(a+" either has no property '"+c+"', or the property is inaccessible.");else if(a=typeof e,e=G[a],e==voi [...]
-a+"'");else{for(var f=[this],g=0;g<arguments.length;g++)f.push(arguments[g]);if(e=F(e,f)){m.appendChild(e.domElement);d.push(e);DAT.GUI.allControllers.push(e);a!="function"&&DAT.GUI.saveIndex<DAT.GUI.savedValues.length&&(e.setValue(DAT.GUI.savedValues[DAT.GUI.saveIndex]),DAT.GUI.saveIndex++);A();q||(k=h);if(!b)try{if(arguments.callee.caller==window.onload)l=n=k=h,m.style.height=l+"px"}catch(i){}return e}else DAT.GUI.error("Error creating controller for '"+c+"'.")}};var A=function(){h=0;f [...]
-d[a].domElement.offsetHeight;m.style.overflowY=h-1>k?"auto":"hidden"},G={number:DAT.GUI.ControllerNumber,string:DAT.GUI.ControllerString,"boolean":DAT.GUI.ControllerBoolean,"function":DAT.GUI.ControllerFunction};this.reset=function(){for(var a=0,b=DAT.GUI.allControllers.length;a<b;a++)DAT.GUI.allControllers[a].reset()};this.toggle=function(){g?this.close():this.open()};this.open=function(){o.innerHTML=p||"Close Controls";n=k;clearTimeout(r);s();B();g=!0};this.close=function(){o.innerHTML [...]
-n=0;clearTimeout(r);s();B();g=!1};this.name=function(a){p=a;o.innerHTML=a};this.appearanceVars=function(){return[g,e,k,m.scrollTop]};var s=function(){l=m.offsetHeight;l+=(n-l)*0.6;Math.abs(l-n)<1?l=n:r=setTimeout(s,1E3/30);m.style.height=Math.round(l)+"px";A()},B=function(){j.domElement.style.width=e-1+"px";setTimeout(function(){j.domElement.style.width=e+"px"},1)};if(DAT.GUI.guiIndex<DAT.GUI.savedAppearanceVars.length){e=parseInt(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][1]);j.domEl [...]
-e+"px";k=parseInt(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][2]);q=!0;if(eval(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][0])==!0){var l=k,H=DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][3];setTimeout(function(){m.scrollTop=H},0);if(DAT.GUI.scrollTop>-1)document.body.scrollTop=DAT.GUI.scrollTop;n=k;this.open()}DAT.GUI.guiIndex++}DAT.GUI.allGuis.push(this);if(DAT.GUI.allGuis.length==1&&(window.addEventListener("keyup",function(a){!DAT.GUI.supressHotKeys&&a.keyCode==72&&DAT.GUI.toggle [...]
-DAT.GUI.inlineCSS))a=document.createElement("style"),a.setAttribute("type","text/css"),a.innerHTML=DAT.GUI.inlineCSS,document.head.insertBefore(a,document.head.firstChild)};DAT.GUI.hidden=!1;DAT.GUI.autoPlace=!0;DAT.GUI.autoPlaceContainer=null;DAT.GUI.allControllers=[];DAT.GUI.allGuis=[];DAT.GUI.supressHotKeys=!1;DAT.GUI.toggleHide=function(){DAT.GUI.hidden?DAT.GUI.open():DAT.GUI.close()};
-DAT.GUI.open=function(){DAT.GUI.hidden=!1;for(var a in DAT.GUI.allGuis)DAT.GUI.allGuis[a].domElement.style.display="block"};DAT.GUI.close=function(){DAT.GUI.hidden=!0;for(var a in DAT.GUI.allGuis)DAT.GUI.allGuis[a].domElement.style.display="none"};DAT.GUI.saveURL=function(){var a=DAT.GUI.replaceGetVar("saveString",DAT.GUI.getSaveString());window.location=a};DAT.GUI.scrollTop=-1;
-DAT.GUI.load=function(a){var a=a.split(","),b=parseInt(a[0]);DAT.GUI.scrollTop=parseInt(a[1]);for(var d=0;d<b;d++){var c=a.splice(2,4);DAT.GUI.savedAppearanceVars.push(c)}DAT.GUI.savedValues=a.splice(2,a.length)};DAT.GUI.savedValues=[];DAT.GUI.savedAppearanceVars=[];
-DAT.GUI.getSaveString=function(){var a=[],b;a.push(DAT.GUI.allGuis.length);a.push(document.body.scrollTop);for(b in DAT.GUI.allGuis)for(var d=DAT.GUI.allGuis[b].appearanceVars(),c=0;c<d.length;c++)a.push(d[c]);for(b in DAT.GUI.allControllers)DAT.GUI.allControllers[b].type!="function"&&(d=DAT.GUI.allControllers[b].getValue(),DAT.GUI.allControllers[b].type=="number"&&(d=DAT.GUI.roundToDecimal(d,4)),a.push(d));return a.join(",")};
-DAT.GUI.getVarFromURL=function(a){for(var b,d=window.location.href.slice(window.location.href.indexOf("?")+1).split("&"),c=0;c<d.length;c++)if(b=d[c].split("="),b!=void 0&&b[0]==a)return b[1];return null};
-DAT.GUI.replaceGetVar=function(a,b){for(var d,c=window.location.href,i=window.location.href.slice(window.location.href.indexOf("?")+1).split("&"),f=0;f<i.length;f++)if(d=i[f].split("="),d!=void 0&&d[0]==a)return c.replace(d[1],b);return window.location.href.indexOf("?")!=-1?c+"&"+a+"="+b:c+"?"+a+"="+b};DAT.GUI.saveIndex=0;DAT.GUI.guiIndex=0;DAT.GUI.showSaveString=function(){alert(DAT.GUI.getSaveString())};
-DAT.GUI.makeUnselectable=function(a){if(!(a==void 0||a.style==void 0)){a.onselectstart=function(){return!1};a.style.MozUserSelect="none";a.style.KhtmlUserSelect="none";a.unselectable="on";for(var a=a.childNodes,b=0;b<a.length;b++)DAT.GUI.makeUnselectable(a[b])}};DAT.GUI.makeSelectable=function(a){if(!(a==void 0||a.style==void 0)){a.onselectstart=function(){};a.style.MozUserSelect="auto";a.style.KhtmlUserSelect="auto";a.unselectable="off";for(var a=a.childNodes,b=0;b<a.length;b++)DAT.GUI. [...]
-DAT.GUI.map=function(a,b,d,c,i){return c+(i-c)*((a-b)/(d-b))};DAT.GUI.constrain=function(a,b,d){a<b?a=b:a>d&&(a=d);return a};DAT.GUI.error=function(a){typeof console.error=="function"&&console.error("[DAT.GUI ERROR] "+a)};DAT.GUI.roundToDecimal=function(a,b){var d=Math.pow(10,b);return Math.round(a*d)/d};DAT.GUI.extendController=function(a){a.prototype=new DAT.GUI.Controller;a.prototype.constructor=a};DAT.GUI.addClass=function(a,b){DAT.GUI.hasClass(a,b)||(a.className+=" "+b)};
-DAT.GUI.hasClass=function(a,b){return a.className.indexOf(b)!=-1};DAT.GUI.removeClass=function(a,b){a.className=a.className.replace(RegExp(" "+b,"g"),"")};DAT.GUI.getVarFromURL("saveString")!=null&&DAT.GUI.load(DAT.GUI.getVarFromURL("saveString"));
-DAT.GUI.Controller=function(){this.parent=arguments[0];this.object=arguments[1];this.propertyName=arguments[2];if(arguments.length>0)this.initialValue=this.object[this.propertyName];this.domElement=document.createElement("div");this.domElement.setAttribute("class","guidat-controller "+this.type);this.propertyNameElement=document.createElement("span");this.propertyNameElement.setAttribute("class","guidat-propertyname");this.name(this.propertyName);this.domElement.appendChild(this.property [...]
-DAT.GUI.makeUnselectable(this.domElement)};DAT.GUI.Controller.prototype.changeFunction=null;DAT.GUI.Controller.prototype.finishChangeFunction=null;DAT.GUI.Controller.prototype.name=function(a){this.propertyNameElement.innerHTML=a;return this};DAT.GUI.Controller.prototype.reset=function(){this.setValue(this.initialValue);return this};DAT.GUI.Controller.prototype.listen=function(){this.parent.listenTo(this);return this};DAT.GUI.Controller.prototype.unlisten=function(){this.parent.unlistenT [...]
-DAT.GUI.Controller.prototype.setValue=function(a){if(this.object[this.propertyName]!=void 0)this.object[this.propertyName]=a;else{var b={};b[this.propertyName]=a;this.object.set(b)}this.changeFunction!=null&&this.changeFunction.call(this,a);this.updateDisplay();return this};DAT.GUI.Controller.prototype.getValue=function(){var a=this.object[this.propertyName];a==void 0&&(a=this.object.get(this.propertyName));return a};DAT.GUI.Controller.prototype.updateDisplay=function(){};
-DAT.GUI.Controller.prototype.onChange=function(a){this.changeFunction=a;return this};DAT.GUI.Controller.prototype.onFinishChange=function(a){this.finishChangeFunction=a;return this};
-DAT.GUI.Controller.prototype.options=function(){var a=this,b=document.createElement("select");if(arguments.length==1){var d=arguments[0],c;for(c in d){var i=document.createElement("option");i.innerHTML=c;i.setAttribute("value",d[c]);if(arguments[c]==this.getValue())i.selected=!0;b.appendChild(i)}}else for(c=0;c<arguments.length;c++){i=document.createElement("option");i.innerHTML=arguments[c];i.setAttribute("value",arguments[c]);if(arguments[c]==this.getValue())i.selected=!0;b.appendChild [...]
-function(){a.setValue(this.value);a.finishChangeFunction!=null&&a.finishChangeFunction.call(this,a.getValue())},!1);a.domElement.appendChild(b);return this};
-DAT.GUI.ControllerBoolean=function(){this.type="boolean";DAT.GUI.Controller.apply(this,arguments);var a=this,b=document.createElement("input");b.setAttribute("type","checkbox");b.checked=this.getValue();this.setValue(this.getValue());this.domElement.addEventListener("click",function(d){b.checked=!b.checked;d.preventDefault();a.setValue(b.checked)},!1);b.addEventListener("mouseup",function(){b.checked=!b.checked},!1);this.domElement.style.cursor="pointer";this.propertyNameElement.style.cu [...]
-this.domElement.appendChild(b);this.updateDisplay=function(){b.checked=a.getValue()};this.setValue=function(a){if(typeof a!="boolean")try{a=eval(a)}catch(b){}return DAT.GUI.Controller.prototype.setValue.call(this,a)}};DAT.GUI.extendController(DAT.GUI.ControllerBoolean);
-DAT.GUI.ControllerFunction=function(){this.type="function";var a=this;DAT.GUI.Controller.apply(this,arguments);this.domElement.addEventListener("click",function(){a.fire()},!1);this.domElement.style.cursor="pointer";this.propertyNameElement.style.cursor="pointer";var b=null;this.onFire=function(a){b=a;return this};this.fire=function(){b!=null&&b.call(this);a.object[a.propertyName].call(a.object)}};DAT.GUI.extendController(DAT.GUI.ControllerFunction);
-DAT.GUI.ControllerNumber=function(){this.type="number";DAT.GUI.Controller.apply(this,arguments);var a=this,b=!1,d=!1,c=0,i=0,f=arguments[3],h=arguments[4],j=arguments[5];this.min=function(){var b=!1;f==void 0&&h!=void 0&&(b=!0);if(arguments.length==0)return f;else f=arguments[0];b&&(q(),j==void 0&&(j=(h-f)*0.01));return a};this.max=function(){var b=!1;f!=void 0&&h==void 0&&(b=!0);if(arguments.length==0)return h;else h=arguments[0];b&&(q(),j==void 0&&(j=(h-f)*0.01));return a};this.step=fu [...]
-0)return j;else j=arguments[0];return a};this.getMin=function(){return f};this.getMax=function(){return h};this.getStep=function(){return j==void 0?h!=void 0&&f!=void 0?(h-f)/100:1:j};var g=document.createElement("input");g.setAttribute("id",this.propertyName);g.setAttribute("type","text");g.setAttribute("value",this.getValue());j&&g.setAttribute("step",j);this.domElement.appendChild(g);var e,q=function(){e=new DAT.GUI.ControllerNumberSlider(a,f,h,j,a.getValue());a.domElement.appendChild [...]
-f!=void 0&&h!=void 0&&q();g.addEventListener("blur",function(){var b=parseFloat(this.value);e&&DAT.GUI.removeClass(a.domElement,"active");isNaN(b)||a.setValue(b)},!1);g.addEventListener("mousewheel",function(b){b.preventDefault();a.setValue(a.getValue()+Math.abs(b.wheelDeltaY)/b.wheelDeltaY*a.getStep());return!1},!1);g.addEventListener("mousedown",function(a){i=c=a.pageY;DAT.GUI.makeSelectable(g);document.addEventListener("mousemove",p,!1);document.addEventListener("mouseup",k,!1)},!1);g [...]
-function(b){switch(b.keyCode){case 13:b=parseFloat(this.value);a.setValue(b);break;case 38:b=a.getValue()+a.getStep();a.setValue(b);break;case 40:b=a.getValue()-a.getStep(),a.setValue(b)}},!1);var k=function(){document.removeEventListener("mousemove",p,!1);DAT.GUI.makeSelectable(g);a.finishChangeFunction!=null&&a.finishChangeFunction.call(this,a.getValue());d=b=!1;document.removeEventListener("mouseup",k,!1)},p=function(e){i=c;c=e.pageY;var f=i-c;!b&&!d&&(f==0?b=!0:d=!0);if(b)return!0;DA [...]
-"active");DAT.GUI.makeUnselectable(a.parent.domElement);DAT.GUI.makeUnselectable(g);e.preventDefault();e=a.getValue()+f*a.getStep();a.setValue(e);return!1};this.options=function(){a.noSlider();a.domElement.removeChild(g);return DAT.GUI.Controller.prototype.options.apply(this,arguments)};this.noSlider=function(){e&&a.domElement.removeChild(e.domElement);return this};this.setValue=function(a){a=parseFloat(a);f!=void 0&&a<=f?a=f:h!=void 0&&a>=h&&(a=h);return DAT.GUI.Controller.prototype.set [...]
-a)};this.updateDisplay=function(){g.value=DAT.GUI.roundToDecimal(a.getValue(),4);if(e)e.value=a.getValue()}};DAT.GUI.extendController(DAT.GUI.ControllerNumber);
-DAT.GUI.ControllerNumberSlider=function(a,b,d,c,i){var f=!1,h=this;this.domElement=document.createElement("div");this.domElement.setAttribute("class","guidat-slider-bg");this.fg=document.createElement("div");this.fg.setAttribute("class","guidat-slider-fg");this.domElement.appendChild(this.fg);var j=function(b){if(f){var c;c=h.domElement;var d=0,g=0;if(c.offsetParent){do d+=c.offsetLeft,g+=c.offsetTop;while(c=c.offsetParent);c=[d,g]}else c=void 0;b=DAT.GUI.map(b.pageX,c[0],c[0]+h.domEleme [...]
-a.getMin(),a.getMax());b=Math.round(b/a.getStep())*a.getStep();a.setValue(b)}};this.domElement.addEventListener("mousedown",function(b){f=!0;DAT.GUI.addClass(a.domElement,"active");j(b);document.addEventListener("mouseup",g,!1)},!1);var g=function(){DAT.GUI.removeClass(a.domElement,"active");f=!1;a.finishChangeFunction!=null&&a.finishChangeFunction.call(this,a.getValue());document.removeEventListener("mouseup",g,!1)};this.__defineSetter__("value",function(b){this.fg.style.width=DAT.GUI.m [...]
-a.getMax(),0,100)+"%"});document.addEventListener("mousemove",j,!1);this.value=i};
-DAT.GUI.ControllerString=function(){this.type="string";var a=this;DAT.GUI.Controller.apply(this,arguments);var b=document.createElement("input"),d=this.getValue();b.setAttribute("value",d);b.setAttribute("spellcheck","false");this.domElement.addEventListener("mouseup",function(){b.focus();b.select()},!1);b.addEventListener("keyup",function(c){c.keyCode==13&&a.finishChangeFunction!=null&&(a.finishChangeFunction.call(this,a.getValue()),b.blur());a.setValue(b.value)},!1);b.addEventListener( [...]
-function(){DAT.GUI.makeSelectable(b)},!1);b.addEventListener("blur",function(){DAT.GUI.supressHotKeys=!1;a.finishChangeFunction!=null&&a.finishChangeFunction.call(this,a.getValue())},!1);b.addEventListener("focus",function(){DAT.GUI.supressHotKeys=!0},!1);this.updateDisplay=function(){b.value=a.getValue()};this.options=function(){a.domElement.removeChild(b);return DAT.GUI.Controller.prototype.options.apply(this,arguments)};this.domElement.appendChild(b)};DAT.GUI.extendController(DAT.GUI. [...]
-DAT.GUI.inlineCSS="#guidat { position: fixed; top: 0; right: 0; width: auto; z-index: 1001; text-align: right; } .guidat { color: #fff; opacity: 0.97; text-align: left; float: right; margin-right: 20px; margin-bottom: 20px; background-color: #fff; } .guidat, .guidat input { font: 9.5px Lucida Grande, sans-serif; } .guidat-controllers { height: 300px; overflow-y: auto; overflow-x: hidden; background-color: rgba(0, 0, 0, 0.1); } a.guidat-toggle:link, a.guidat-toggle:visited, a.guidat-toggl [...]
diff --git a/emperor/support_files/js/js/Detector.js b/emperor/support_files/js/js/Detector.js
deleted file mode 100644
index 2d38906..0000000
--- a/emperor/support_files/js/js/Detector.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mr.doob / http://mrdoob.com/
- */
-
-Detector = {
-
-	canvas : !! window.CanvasRenderingContext2D,
-	webgl : ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
-	workers : !! window.Worker,
-	fileapi : window.File && window.FileReader && window.FileList && window.Blob,
-
-	getWebGLErrorMessage : function () {
-
-		var domElement = document.createElement( 'div' );
-
-		domElement.style.fontFamily = 'monospace';
-		domElement.style.fontSize = '13px';
-		domElement.style.textAlign = 'center';
-		domElement.style.background = '#eee';
-		domElement.style.color = '#000';
-		domElement.style.padding = '1em';
-		domElement.style.width = '475px';
-		domElement.style.margin = '5em auto 0';
-
-		if ( ! this.webgl ) {
-
-			domElement.innerHTML = window.WebGLRenderingContext ? [
-				'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a>.<br />',
-				'Find out how to get it <a href="http://get.webgl.org/">here</a>.'
-			].join( '\n' ) : [
-				'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a>.<br/>',
-				'Find out how to get it <a href="http://get.webgl.org/">here</a>.'
-			].join( '\n' );
-
-		}
-
-		return domElement;
-
-	},
-
-	addGetWebGLMessage : function ( parameters ) {
-
-		var parent, id, domElement;
-
-		parameters = parameters || {};
-
-		parent = parameters.parent !== undefined ? parameters.parent : document.body;
-		id = parameters.id !== undefined ? parameters.id : 'oldie';
-
-		domElement = Detector.getWebGLErrorMessage();
-		domElement.id = id;
-
-		parent.appendChild( domElement );
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/ImprovedNoise.js b/emperor/support_files/js/js/ImprovedNoise.js
deleted file mode 100644
index 08246a6..0000000
--- a/emperor/support_files/js/js/ImprovedNoise.js
+++ /dev/null
@@ -1,71 +0,0 @@
-// http://mrl.nyu.edu/~perlin/noise/
-
-var ImprovedNoise = function () {
-
-	var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,
-		 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,
-		 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,
-		 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,
-		 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,
-		 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,
-		 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,
-		 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,
-		 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,
-		 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
-
-	for (var i=0; i < 256 ; i++) {
-
-		p[256+i] = p[i];
-
-	}
-
-	function fade(t) {
-
-		return t * t * t * (t * (t * 6 - 15) + 10);
-
-	}
-
-	function lerp(t, a, b) {
-
-		return a + t * (b - a);
-
-	}
-
-	function grad(hash, x, y, z) {
-
-		var h = hash & 15;
-		var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
-		return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
-
-	}
-
-	return {
-
-		noise: function (x, y, z) {
-
-			var floorX = ~~x, floorY = ~~y, floorZ = ~~z;
-
-			var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;
-
-			x -= floorX;
-			y -= floorY;
-			z -= floorZ;
-
-			var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1;
-
-			var u = fade(x), v = fade(y), w = fade(z);
-
-			var A = p[X]+Y, AA = p[A]+Z, AB = p[A+1]+Z, B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;
-
-			return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), 
-							grad(p[BA], xMinus1, y, z)),
-						lerp(u, grad(p[AB], x, yMinus1, z),
-							grad(p[BB], xMinus1, yMinus1, z))),
-					lerp(v, lerp(u, grad(p[AA+1], x, y, zMinus1),
-							grad(p[BA+1], xMinus1, y, z-1)),
-						lerp(u, grad(p[AB+1], x, yMinus1, zMinus1),
-							grad(p[BB+1], xMinus1, yMinus1, zMinus1))));
-
-		}
-	}
-}
diff --git a/emperor/support_files/js/js/PRNG.js b/emperor/support_files/js/js/PRNG.js
deleted file mode 100644
index 038b7ba..0000000
--- a/emperor/support_files/js/js/PRNG.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Park-Miller-Carta Pseudo-Random Number Generator
-// https://github.com/pnitsch/BitmapData.js/blob/master/js/BitmapData.js
-
-var PRNG = function () {
-
-	this.seed = 1;
-	this.next = function() { return (this.gen() / 2147483647); };
-	this.nextRange = function(min, max)	{ return min + ((max - min) * this.next()) };
-	this.gen = function() { return this.seed = (this.seed * 16807) % 2147483647; };
-
-};
diff --git a/emperor/support_files/js/js/RequestAnimationFrame.js b/emperor/support_files/js/js/RequestAnimationFrame.js
deleted file mode 100644
index 77f85c5..0000000
--- a/emperor/support_files/js/js/RequestAnimationFrame.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Provides requestAnimationFrame in a cross browser way.
- * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
- */
-
-if ( !window.requestAnimationFrame ) {
-
-	window.requestAnimationFrame = ( function() {
-
-		return window.webkitRequestAnimationFrame ||
-		window.mozRequestAnimationFrame ||
-		window.oRequestAnimationFrame ||
-		window.msRequestAnimationFrame ||
-		function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
-
-			window.setTimeout( callback, 1000 / 60 );
-
-		};
-
-	} )();
-
-}
diff --git a/emperor/support_files/js/js/ShaderExtras.js b/emperor/support_files/js/js/ShaderExtras.js
deleted file mode 100644
index 0fcda20..0000000
--- a/emperor/support_files/js/js/ShaderExtras.js
+++ /dev/null
@@ -1,1779 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- * ShaderExtras currently contains:
- *
- *	screen
- *	convolution
- *	film
- * 	bokeh
- *  sepia
- *	dotscreen
- *	vignette
- *  bleachbypass
- *	basic
- *  dofmipmap
- *  focus
- *  triangleBlur
- *  horizontalBlur + verticalBlur
- *  horizontalTiltShift + verticalTiltShift
- *  blend
- *  fxaa
- *  luminosity
- *  colorCorrection
- *  normalmap
- *  ssao
- *  colorify
- *  unpackDepthRGBA
- */
-
-THREE.ShaderExtras = {
-
-	/* -------------------------------------------------------------------------
-	//	Full-screen textured quad shader
-	 ------------------------------------------------------------------------- */
-
-	'screen': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			opacity:  { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 texel = texture2D( tDiffuse, vUv );",
-				"gl_FragColor = opacity * texel;",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* ------------------------------------------------------------------------
-	//	Convolution shader
-	//	  - ported from o3d sample to WebGL / GLSL
-	//			http://o3d.googlecode.com/svn/trunk/samples/convolution.html
-	------------------------------------------------------------------------ */
-
-	'convolution': {
-
-		uniforms: {
-
-			"tDiffuse" : 		{ type: "t", value: 0, texture: null },
-			"uImageIncrement" : { type: "v2", value: new THREE.Vector2( 0.001953125, 0.0 ) },
-			"cKernel" : 		{ type: "fv1", value: [] }
-
-		},
-
-		vertexShader: [
-
-			//"#define KERNEL_SIZE 25.0",
-
-			"uniform vec2 uImageIncrement;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = uv - ( ( KERNEL_SIZE - 1.0 ) / 2.0 ) * uImageIncrement;",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			//"#define KERNEL_SIZE 25",
-			"uniform float cKernel[ KERNEL_SIZE ];",
-
-			"uniform sampler2D tDiffuse;",
-			"uniform vec2 uImageIncrement;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec2 imageCoord = vUv;",
-				"vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );",
-
-				"for( int i = 0; i < KERNEL_SIZE; i ++ ) {",
-
-					"sum += texture2D( tDiffuse, imageCoord ) * cKernel[ i ];",
-					"imageCoord += uImageIncrement;",
-
-				"}",
-
-				"gl_FragColor = sum;",
-
-			"}"
-
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-
-	// Film grain & scanlines shader
-
-	//	- ported from HLSL to WebGL / GLSL
-	//	  http://www.truevision3d.com/forums/showcase/staticnoise_colorblackwhite_scanline_shaders-t18698.0.html
-
-	// Screen Space Static Postprocessor
-	//
-	// Produces an analogue noise overlay similar to a film grain / TV static
-	//
-	// Original implementation and noise algorithm
-	// Pat 'Hawthorne' Shearon
-	//
-	// Optimized scanlines + noise version with intensity scaling
-	// Georg 'Leviathan' Steinrohder
-
-	// This version is provided under a Creative Commons Attribution 3.0 License
-	// http://creativecommons.org/licenses/by/3.0/
-	 ------------------------------------------------------------------------- */
-
-	'film': {
-
-		uniforms: {
-
-			tDiffuse:   { type: "t", value: 0, texture: null },
-			time: 	    { type: "f", value: 0.0 },
-			nIntensity: { type: "f", value: 0.5 },
-			sIntensity: { type: "f", value: 0.05 },
-			sCount: 	{ type: "f", value: 4096 },
-			grayscale:  { type: "i", value: 1 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			// control parameter
-			"uniform float time;",
-
-			"uniform bool grayscale;",
-
-			// noise effect intensity value (0 = no effect, 1 = full effect)
-			"uniform float nIntensity;",
-
-			// scanlines effect intensity value (0 = no effect, 1 = full effect)
-			"uniform float sIntensity;",
-
-			// scanlines effect count value (0 = no effect, 4096 = full effect)
-			"uniform float sCount;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				// sample the source
-				"vec4 cTextureScreen = texture2D( tDiffuse, vUv );",
-
-				// make some noise
-				"float x = vUv.x * vUv.y * time *  1000.0;",
-				"x = mod( x, 13.0 ) * mod( x, 123.0 );",
-				"float dx = mod( x, 0.01 );",
-
-				// add noise
-				"vec3 cResult = cTextureScreen.rgb + cTextureScreen.rgb * clamp( 0.1 + dx * 100.0, 0.0, 1.0 );",
-
-				// get us a sine and cosine
-				"vec2 sc = vec2( sin( vUv.y * sCount ), cos( vUv.y * sCount ) );",
-
-				// add scanlines
-				"cResult += cTextureScreen.rgb * vec3( sc.x, sc.y, sc.x ) * sIntensity;",
-
-				// interpolate between source and result by intensity
-				"cResult = cTextureScreen.rgb + clamp( nIntensity, 0.0,1.0 ) * ( cResult - cTextureScreen.rgb );",
-
-				// convert to grayscale if desired
-				"if( grayscale ) {",
-
-					"cResult = vec3( cResult.r * 0.3 + cResult.g * 0.59 + cResult.b * 0.11 );",
-
-				"}",
-
-				"gl_FragColor =  vec4( cResult, cTextureScreen.a );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-
-	/* -------------------------------------------------------------------------
-	//	Depth-of-field shader with bokeh
-	//	ported from GLSL shader by Martins Upitis
-	//	http://artmartinsh.blogspot.com/2010/02/glsl-lens-blur-filter-with-bokeh.html
-	 ------------------------------------------------------------------------- */
-
-	'bokeh'	: {
-
-	uniforms: { tColor:   { type: "t", value: 0, texture: null },
-				tDepth:   { type: "t", value: 1, texture: null },
-				focus:    { type: "f", value: 1.0 },
-				aspect:   { type: "f", value: 1.0 },
-				aperture: { type: "f", value: 0.025 },
-				maxblur:  { type: "f", value: 1.0 },
-			  },
-
-	vertexShader: [
-
-	"varying vec2 vUv;",
-
-	"void main() {",
-
-		"vUv = vec2( uv.x, 1.0 - uv.y );",
-		"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-	"}"
-
-	].join("\n"),
-
-	fragmentShader: [
-
-	"varying vec2 vUv;",
-
-	"uniform sampler2D tColor;",
-	"uniform sampler2D tDepth;",
-
-	"uniform float maxblur;",  	// max blur amount
-	"uniform float aperture;",	// aperture - bigger values for shallower depth of field
-
-	"uniform float focus;",
-	"uniform float aspect;",
-
-	"void main() {",
-
-		"vec2 aspectcorrect = vec2( 1.0, aspect );",
-
-		"vec4 depth1 = texture2D( tDepth, vUv );",
-
-		"float factor = depth1.x - focus;",
-
-		"vec2 dofblur = vec2 ( clamp( factor * aperture, -maxblur, maxblur ) );",
-
-		"vec2 dofblur9 = dofblur * 0.9;",
-		"vec2 dofblur7 = dofblur * 0.7;",
-		"vec2 dofblur4 = dofblur * 0.4;",
-
-		"vec4 col = vec4( 0.0 );",
-
-		"col += texture2D( tColor, vUv.xy );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,   0.4  ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.15,  0.37 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29,  0.29 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.37,  0.15 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.40,  0.0  ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.37, -0.15 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29, -0.29 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,  -0.4  ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.15,  0.37 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29,  0.29 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.37,  0.15 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.4,   0.0  ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.15, -0.37 ) * aspectcorrect ) * dofblur );",
-
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.15,  0.37 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.37,  0.15 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.37, -0.15 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.15,  0.37 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.37,  0.15 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur9 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.15, -0.37 ) * aspectcorrect ) * dofblur9 );",
-
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29,  0.29 ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.40,  0.0  ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29, -0.29 ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,  -0.4  ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29,  0.29 ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.4,   0.0  ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur7 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,   0.4  ) * aspectcorrect ) * dofblur7 );",
-
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29,  0.29 ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.4,   0.0  ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.29, -0.29 ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,  -0.4  ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29,  0.29 ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.4,   0.0  ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur4 );",
-		"col += texture2D( tColor, vUv.xy + ( vec2(  0.0,   0.4  ) * aspectcorrect ) * dofblur4 );",
-
-		"gl_FragColor = col / 41.0;",
-		"gl_FragColor.a = 1.0;",
-
-	"}"
-
-	].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Depth-of-field shader using mipmaps
-	//	- from Matt Handley @applmak
-	//	- requires power-of-2 sized render target with enabled mipmaps
-	 ------------------------------------------------------------------------- */
-
-	'dofmipmap': {
-
-		uniforms: {
-
-			tColor:   { type: "t", value: 0, texture: null },
-			tDepth:   { type: "t", value: 1, texture: null },
-			focus:    { type: "f", value: 1.0 },
-			maxblur:  { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float focus;",
-			"uniform float maxblur;",
-
-			"uniform sampler2D tColor;",
-			"uniform sampler2D tDepth;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 depth = texture2D( tDepth, vUv );",
-
-				"float factor = depth.x - focus;",
-
-				"vec4 col = texture2D( tColor, vUv, 2.0 * maxblur * abs( focus - depth.x ) );",
-
-				"gl_FragColor = col;",
-				"gl_FragColor.a = 1.0;",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Sepia tone shader
-	//  - based on glfx.js sepia shader
-	//		https://github.com/evanw/glfx.js
-	 ------------------------------------------------------------------------- */
-
-	'sepia': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			amount:   { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float amount;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 color = texture2D( tDiffuse, vUv );",
-				"vec3 c = color.rgb;",
-
-				"color.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );",
-				"color.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );",
-				"color.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );",
-
-				"gl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Dot screen shader
-	//  - based on glfx.js sepia shader
-	//		https://github.com/evanw/glfx.js
-	 ------------------------------------------------------------------------- */
-
-	'dotscreen': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			tSize:    { type: "v2", value: new THREE.Vector2( 256, 256 ) },
-			center:   { type: "v2", value: new THREE.Vector2( 0.5, 0.5 ) },
-			angle:	  { type: "f", value: 1.57 },
-			scale:	  { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec2 center;",
-			"uniform float angle;",
-			"uniform float scale;",
-			"uniform vec2 tSize;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"float pattern() {",
-
-				"float s = sin( angle ), c = cos( angle );",
-
-				"vec2 tex = vUv * tSize - center;",
-				"vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;",
-
-				"return ( sin( point.x ) * sin( point.y ) ) * 4.0;",
-
-			"}",
-
-			"void main() {",
-
-				"vec4 color = texture2D( tDiffuse, vUv );",
-
-				"float average = ( color.r + color.g + color.b ) / 3.0;",
-
-				"gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* ------------------------------------------------------------------------------------------------
-	//	Vignette shader
-	//	- based on PaintEffect postprocess from ro.me
-	//		http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js
-	 ------------------------------------------------------------------------------------------------ */
-
-	'vignette': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			offset:   { type: "f", value: 1.0 },
-			darkness: { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float offset;",
-			"uniform float darkness;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				// Eskil's vignette
-
-				"vec4 texel = texture2D( tDiffuse, vUv );",
-				"vec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );",
-				"gl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );",
-
-				/*
-				// alternative version from glfx.js
-				// this one makes more "dusty" look (as opposed to "burned")
-
-				"vec4 color = texture2D( tDiffuse, vUv );",
-				"float dist = distance( vUv, vec2( 0.5 ) );",
-				"color.rgb *= smoothstep( 0.8, offset * 0.799, dist *( darkness + offset ) );",
-				"gl_FragColor = color;",
-				*/
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Bleach bypass shader [http://en.wikipedia.org/wiki/Bleach_bypass]
-	//	- based on Nvidia example
-	//		http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#post_bleach_bypass
-	 ------------------------------------------------------------------------- */
-
-	'bleachbypass': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			opacity:  { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 base = texture2D( tDiffuse, vUv );",
-
-				"vec3 lumCoeff = vec3( 0.25, 0.65, 0.1 );",
-				"float lum = dot( lumCoeff, base.rgb );",
-				"vec3 blend = vec3( lum );",
-
-				"float L = min( 1.0, max( 0.0, 10.0 * ( lum - 0.45 ) ) );",
-
-				"vec3 result1 = 2.0 * base.rgb * blend;",
-				"vec3 result2 = 1.0 - 2.0 * ( 1.0 - blend ) * ( 1.0 - base.rgb );",
-
-				"vec3 newColor = mix( result1, result2, L );",
-
-				"float A2 = opacity * base.a;",
-				"vec3 mixRGB = A2 * newColor.rgb;",
-				"mixRGB += ( ( 1.0 - A2 ) * base.rgb );",
-
-				"gl_FragColor = vec4( mixRGB, base.a );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* --------------------------------------------------------------------------------------------------
-	//	Focus shader
-	//	- based on PaintEffect postprocess from ro.me
-	//		http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js
-	 -------------------------------------------------------------------------------------------------- */
-
-	'focus': {
-
-		uniforms : {
-
-			"tDiffuse": 		{ type: "t", value: 0, texture: null },
-			"screenWidth": 		{ type: "f", value: 1024 },
-			"screenHeight": 	{ type: "f", value: 1024 },
-			"sampleDistance": 	{ type: "f", value: 0.94 },
-			"waveFactor": 		{ type: "f", value: 0.00125 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float screenWidth;",
-			"uniform float screenHeight;",
-			"uniform float sampleDistance;",
-			"uniform float waveFactor;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 color, org, tmp, add;",
-				"float sample_dist, f;",
-				"vec2 vin;",
-				"vec2 uv = vUv;",
-
-				"add += color = org = texture2D( tDiffuse, uv );",
-
-				"vin = ( uv - vec2( 0.5 ) ) * vec2( 1.4 );",
-				"sample_dist = dot( vin, vin ) * 2.0;",
-
-				"f = ( waveFactor * 100.0 + sample_dist ) * sampleDistance * 4.0;",
-
-				"vec2 sampleSize = vec2(  1.0 / screenWidth, 1.0 / screenHeight ) * vec2( f );",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( 0.111964, 0.993712 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( 0.846724, 0.532032 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( 0.943883, -0.330279 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( 0.330279, -0.943883 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( -0.532032, -0.846724 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( -0.993712, -0.111964 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"add += tmp = texture2D( tDiffuse, uv + vec2( -0.707107, 0.707107 ) * sampleSize );",
-				"if( tmp.b < color.b ) color = tmp;",
-
-				"color = color * vec4( 2.0 ) - ( add / vec4( 8.0 ) );",
-				"color = color + ( add / vec4( 8.0 ) - color ) * ( vec4( 1.0 ) - vec4( sample_dist * 0.5 ) );",
-
-				"gl_FragColor = vec4( color.rgb * color.rgb * vec3( 0.95 ) + color.rgb, 1.0 );",
-
-			"}"
-
-
-		].join("\n")
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Triangle blur shader
-	//  - based on glfx.js triangle blur shader
-	//		https://github.com/evanw/glfx.js
-
-	// 	A basic blur filter, which convolves the image with a
-	// 	pyramid filter. The pyramid filter is separable and is applied as two
-	//  perpendicular triangle filters.
-	 ------------------------------------------------------------------------- */
-
-	'triangleBlur': {
-
-
-		uniforms : {
-
-			"texture": 	{ type: "t", value: 0, texture: null },
-			"delta": 	{ type: "v2", value:new THREE.Vector2( 1, 1 )  }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-		"#define ITERATIONS 10.0",
-
-		"uniform sampler2D texture;",
-		"uniform vec2 delta;",
-
-		"varying vec2 vUv;",
-
-		"float random( vec3 scale, float seed ) {",
-
-			// use the fragment position for a different seed per-pixel
-
-			"return fract( sin( dot( gl_FragCoord.xyz + seed, scale ) ) * 43758.5453 + seed );",
-
-		"}",
-
-		"void main() {",
-
-			"vec4 color = vec4( 0.0 );",
-
-			"float total = 0.0;",
-
-			// randomize the lookup values to hide the fixed number of samples
-
-			"float offset = random( vec3( 12.9898, 78.233, 151.7182 ), 0.0 );",
-
-			"for ( float t = -ITERATIONS; t <= ITERATIONS; t ++ ) {",
-
-				"float percent = ( t + offset - 0.5 ) / ITERATIONS;",
-				"float weight = 1.0 - abs( percent );",
-
-				"color += texture2D( texture, vUv + delta * percent ) * weight;",
-				"total += weight;",
-
-			"}",
-
-			"gl_FragColor = color / total;",
-
-		"}",
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Simple test shader
-	 ------------------------------------------------------------------------- */
-
-	'basic': {
-
-		uniforms: {},
-
-		vertexShader: [
-
-			"void main() {",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"void main() {",
-
-				"gl_FragColor = vec4( 1.0, 0.0, 0.0, 0.5 );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* --------------------------------------------------------------------------------------------------
-	//	Two pass Gaussian blur filter (horizontal and vertical blur shaders)
-	//	- described in http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
-	//	  and used in http://www.cake23.de/traveling-wavefronts-lit-up.html
-	//
-	//	- 9 samples per pass
-	//	- standard deviation 2.7
-	//	- "h" and "v" parameters should be set to "1 / width" and "1 / height"
-	 -------------------------------------------------------------------------------------------------- */
-
-	'horizontalBlur': {
-
-		uniforms: {
-
-			"tDiffuse": { type: "t", value: 0, texture: null },
-			"h": 		{ type: "f", value: 1.0 / 512.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform float h;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 sum = vec4( 0.0 );",
-
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, 		  	vUv.y ) ) * 0.1633;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * h, vUv.y ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * h, vUv.y ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * h, vUv.y ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * h, vUv.y ) ) * 0.051;",
-
-				"gl_FragColor = sum;",
-
-			"}"
-
-
-		].join("\n")
-
-	},
-
-	'verticalBlur': {
-
-		uniforms: {
-
-			"tDiffuse": { type: "t", value: 0, texture: null },
-			"v": 		{ type: "f", value: 1.0 / 512.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform float v;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 sum = vec4( 0.0 );",
-
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * v ) ) * 0.051;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * v ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * v ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * v ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y			  ) ) * 0.1633;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * v ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * v ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * v ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * v ) ) * 0.051;",
-
-				"gl_FragColor = sum;",
-
-			"}"
-
-
-		].join("\n")
-
-	},
-
-	/* --------------------------------------------------------------------------------------------------
-	//	Simple fake tilt-shift effect, modulating two pass Gaussian blur (see above) by vertical position
-	//
-	//	- 9 samples per pass
-	//	- standard deviation 2.7
-	//	- "h" and "v" parameters should be set to "1 / width" and "1 / height"
-	//	- "r" parameter control where "focused" horizontal line lies
-	 -------------------------------------------------------------------------------------------------- */
-
-	'horizontalTiltShift': {
-
-		uniforms: {
-
-			"tDiffuse": { type: "t", value: 0, texture: null },
-			"h": 		{ type: "f", value: 1.0 / 512.0 },
-			"r": 		{ type: "f", value: 0.35 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform float h;",
-			"uniform float r;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 sum = vec4( 0.0 );",
-
-				"float hh = h * abs( r - vUv.y );",
-
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * hh, vUv.y ) ) * 0.051;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * hh, vUv.y ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * hh, vUv.y ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * hh, vUv.y ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, 		  	 vUv.y ) ) * 0.1633;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * hh, vUv.y ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * hh, vUv.y ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * hh, vUv.y ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * hh, vUv.y ) ) * 0.051;",
-
-				"gl_FragColor = sum;",
-
-			"}"
-
-
-		].join("\n")
-
-	},
-
-	'verticalTiltShift': {
-
-		uniforms: {
-
-			"tDiffuse": { type: "t", value: 0, texture: null },
-			"v": 		{ type: "f", value: 1.0 / 512.0 },
-			"r": 		{ type: "f", value: 0.35 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform float v;",
-			"uniform float r;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 sum = vec4( 0.0 );",
-
-				"float vv = v * abs( r - vUv.y );",
-
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * vv ) ) * 0.051;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * vv ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * vv ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * vv ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y			   ) ) * 0.1633;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * vv ) ) * 0.1531;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * vv ) ) * 0.12245;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * vv ) ) * 0.0918;",
-				"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * vv ) ) * 0.051;",
-
-				"gl_FragColor = sum;",
-
-			"}"
-
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Blend two textures
-	 ------------------------------------------------------------------------- */
-
-	'blend': {
-
-		uniforms: {
-
-			tDiffuse1: { type: "t", value: 0, texture: null },
-			tDiffuse2: { type: "t", value: 1, texture: null },
-			mixRatio:  { type: "f", value: 0.5 },
-			opacity:   { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-			"uniform float mixRatio;",
-
-			"uniform sampler2D tDiffuse1;",
-			"uniform sampler2D tDiffuse2;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 texel1 = texture2D( tDiffuse1, vUv );",
-				"vec4 texel2 = texture2D( tDiffuse2, vUv );",
-				"gl_FragColor = opacity * mix( texel1, texel2, mixRatio );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	NVIDIA FXAA by Timothy Lottes
-	//		http://timothylottes.blogspot.com/2011/06/fxaa3-source-released.html
-	//	- WebGL port by @supereggbert
-	//		http://www.glge.org/demos/fxaa/
-	 ------------------------------------------------------------------------- */
-
-	'fxaa': {
-
-		uniforms: {
-
-			"tDiffuse": 	{ type: "t", value: 0, texture: null },
-			"resolution": 	{ type: "v2", value: new THREE.Vector2( 1 / 1024, 1 / 512 )  }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform vec2 resolution;",
-
-			"varying vec2 vUv;",
-
-			"#define FXAA_REDUCE_MIN   (1.0/128.0)",
-			"#define FXAA_REDUCE_MUL   (1.0/8.0)",
-			"#define FXAA_SPAN_MAX     8.0",
-
-			"void main() {",
-
-				"vec3 rgbNW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ).xyz;",
-				"vec3 rgbNE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ).xyz;",
-				"vec3 rgbSW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ).xyz;",
-				"vec3 rgbSE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ).xyz;",
-				"vec3 rgbM  = texture2D( tDiffuse,  gl_FragCoord.xy  * resolution ).xyz;",
-
-				"vec3 luma = vec3( 0.299, 0.587, 0.114 );",
-
-				"float lumaNW = dot( rgbNW, luma );",
-				"float lumaNE = dot( rgbNE, luma );",
-				"float lumaSW = dot( rgbSW, luma );",
-				"float lumaSE = dot( rgbSE, luma );",
-				"float lumaM  = dot( rgbM,  luma );",
-				"float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );",
-				"float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );",
-
-				"vec2 dir;",
-				"dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));",
-				"dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));",
-
-				"float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );",
-
-				"float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );",
-				"dir = min( vec2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX),",
-					  "max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),",
-							"dir * rcpDirMin)) * resolution;",
-
-				"vec3 rgbA = 0.5 * (",
-					"texture2D( tDiffuse, gl_FragCoord.xy  * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ).xyz +",
-					"texture2D( tDiffuse, gl_FragCoord.xy  * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ).xyz );",
-
-				"vec3 rgbB = rgbA * 0.5 + 0.25 * (",
-					"texture2D( tDiffuse, gl_FragCoord.xy  * resolution + dir * -0.5 ).xyz +",
-					"texture2D( tDiffuse, gl_FragCoord.xy  * resolution + dir * 0.5 ).xyz );",
-
-				"float lumaB = dot( rgbB, luma );",
-
-				"if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) {",
-
-					"gl_FragColor = vec4( rgbA, 1.0 );",
-
-				"} else {",
-
-					"gl_FragColor = vec4( rgbB, 1.0 );",
-
-				"}",
-
-			"}",
-
-		].join("\n"),
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Luminosity
-	//	http://en.wikipedia.org/wiki/Luminosity
-	 ------------------------------------------------------------------------- */
-
-	'luminosity': {
-
-		uniforms: {
-
-			"tDiffuse": 	{ type: "t", value: 0, texture: null }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 texel = texture2D( tDiffuse, vUv );",
-
-				"vec3 luma = vec3( 0.299, 0.587, 0.114 );",
-
-				"float v = dot( texel.xyz, luma );",
-
-				"gl_FragColor = vec4( v, v, v, texel.w );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Color correction
-	 ------------------------------------------------------------------------- */
-
-	'colorCorrection': {
-
-		uniforms: {
-
-			"tDiffuse" : 	{ type: "t", value: 0, texture: null },
-			"powRGB" :		{ type: "v3", value: new THREE.Vector3( 2, 2, 2 ) },
-			"mulRGB" :		{ type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform sampler2D tDiffuse;",
-			"uniform vec3 powRGB;",
-			"uniform vec3 mulRGB;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"gl_FragColor = texture2D( tDiffuse, vUv );",
-				"gl_FragColor.rgb = mulRGB * pow( gl_FragColor.rgb, powRGB );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Normal map shader
-	//	- compute normals from heightmap
-	 ------------------------------------------------------------------------- */
-
-	'normalmap': {
-
-		uniforms: {
-
-			"heightMap"	: { type: "t", value: 0, texture: null },
-			"resolution": { type: "v2", value: new THREE.Vector2( 512, 512 ) },
-			"scale"		: { type: "v2", value: new THREE.Vector2( 1, 1 ) },
-			"height"	: { type: "f", value: 0.05 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float height;",
-			"uniform vec2 resolution;",
-			"uniform sampler2D heightMap;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"float val = texture2D( heightMap, vUv ).x;",
-
-				"float valU = texture2D( heightMap, vUv + vec2( 1.0 / resolution.x, 0.0 ) ).x;",
-				"float valV = texture2D( heightMap, vUv + vec2( 0.0, 1.0 / resolution.y ) ).x;",
-
-				"gl_FragColor = vec4( ( 0.5 * normalize( vec3( val - valU, val - valV, height  ) ) + 0.5 ), 1.0 );",
-
-			"}",
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Screen-space ambient occlusion shader
-	//	- ported from
-	//		SSAO GLSL shader v1.2
-	//		assembled by Martins Upitis (martinsh) (http://devlog-martinsh.blogspot.com)
-	//		original technique is made by ArKano22 (http://www.gamedev.net/topic/550699-ssao-no-halo-artifacts/)
-	//	- modifications
-	//		- modified to use RGBA packed depth texture (use clear color 1,1,1,1 for depth pass)
-	//		- made fog more compatible with three.js linear fog
-	//		- refactoring and optimizations
-	 ------------------------------------------------------------------------- */
-
-	'ssao': {
-
-		uniforms: {
-
-			"tDiffuse": 	{ type: "t", value: 0, texture: null },
-			"tDepth":   	{ type: "t", value: 1, texture: null },
-			"size": 		{ type: "v2", value: new THREE.Vector2( 512, 512 ) },
-			"cameraNear":	{ type: "f", value: 1 },
-			"cameraFar":	{ type: "f", value: 100 },
-			"fogNear":		{ type: "f", value: 5 },
-			"fogFar":		{ type: "f", value: 100 },
-			"fogEnabled":	{ type: "i", value: 0 },
-			"aoClamp":		{ type: "f", value: 0.3 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float cameraNear;",
-			"uniform float cameraFar;",
-
-			"uniform float fogNear;",
-			"uniform float fogFar;",
-
-			"uniform bool fogEnabled;",
-
-			"uniform vec2 size;",		// texture width, height
-			"uniform float aoClamp;", 	// depth clamp - reduces haloing at screen edges
-
-			"uniform sampler2D tDiffuse;",
-			"uniform sampler2D tDepth;",
-
-			"varying vec2 vUv;",
-
-			//"#define PI 3.14159265",
-			"#define DL 2.399963229728653", // PI * ( 3.0 - sqrt( 5.0 ) )
-			"#define EULER 2.718281828459045",
-
-			// helpers
-
-			"float width = size.x;", 	// texture width
-			"float height = size.y;", 	// texture height
-
-			"float cameraFarPlusNear = cameraFar + cameraNear;",
-			"float cameraFarMinusNear = cameraFar - cameraNear;",
-			"float cameraCoef = 2.0 * cameraNear;",
-
-			// user variables
-
-			"const int samples = 8;", 		// ao sample count
-			"const float radius = 5.0;", 	// ao radius
-
-			"const bool useNoise = false;", 		 // use noise instead of pattern for sample dithering
-			"const float noiseAmount = 0.0002;", // dithering amount
-
-			"const float diffArea = 0.4;", 		// self-shadowing reduction
-			"const float gDisplace = 0.4;", 	// gauss bell center
-
-			"const bool onlyAO = false;", 		// use only ambient occlusion pass?
-			"const float lumInfluence = 0.3;",  // how much luminance affects occlusion
-
-			// RGBA depth
-
-			"float unpackDepth( const in vec4 rgba_depth ) {",
-
-				"const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
-				"float depth = dot( rgba_depth, bit_shift );",
-				"return depth;",
-
-			"}",
-
-			// generating noise / pattern texture for dithering
-
-			"vec2 rand( const vec2 coord ) {",
-
-				"vec2 noise;",
-
-				"if ( useNoise ) {",
-
-					"float nx = dot ( coord, vec2( 12.9898, 78.233 ) );",
-					"float ny = dot ( coord, vec2( 12.9898, 78.233 ) * 2.0 );",
-
-					"noise = clamp( fract ( 43758.5453 * sin( vec2( nx, ny ) ) ), 0.0, 1.0 );",
-
-				"} else {",
-
-					"float ff = fract( 1.0 - coord.s * ( width / 2.0 ) );",
-					"float gg = fract( coord.t * ( height / 2.0 ) );",
-
-					"noise = vec2( 0.25, 0.75 ) * vec2( ff ) + vec2( 0.75, 0.25 ) * gg;",
-
-				"}",
-
-				"return ( noise * 2.0  - 1.0 ) * noiseAmount;",
-
-			"}",
-
-			"float doFog() {",
-
-				"float zdepth = unpackDepth( texture2D( tDepth, vUv ) );",
-				"float depth = -cameraFar * cameraNear / ( zdepth * cameraFarMinusNear - cameraFar );",
-
-				"return smoothstep( fogNear, fogFar, depth );",
-
-			"}",
-
-			"float readDepth( const in vec2 coord ) {",
-
-				//"return ( 2.0 * cameraNear ) / ( cameraFar + cameraNear - unpackDepth( texture2D( tDepth, coord ) ) * ( cameraFar - cameraNear ) );",
-				"return cameraCoef / ( cameraFarPlusNear - unpackDepth( texture2D( tDepth, coord ) ) * cameraFarMinusNear );",
-
-
-			"}",
-
-			"float compareDepths( const in float depth1, const in float depth2, inout int far ) {",
-
-				"float garea = 2.0;", 						 // gauss bell width
-				"float diff = ( depth1 - depth2 ) * 100.0;", // depth difference (0-100)
-
-				// reduce left bell width to avoid self-shadowing
-
-				"if ( diff < gDisplace ) {",
-
-					"garea = diffArea;",
-
-				"} else {",
-
-					"far = 1;",
-
-				"}",
-
-				"float dd = diff - gDisplace;",
-				"float gauss = pow( EULER, -2.0 * dd * dd / ( garea * garea ) );",
-				"return gauss;",
-
-			"}",
-
-			"float calcAO( float depth, float dw, float dh ) {",
-
-				"float dd = radius - depth * radius;",
-				"vec2 vv = vec2( dw, dh );",
-
-				"vec2 coord1 = vUv + dd * vv;",
-				"vec2 coord2 = vUv - dd * vv;",
-
-				"float temp1 = 0.0;",
-				"float temp2 = 0.0;",
-
-				"int far = 0;",
-				"temp1 = compareDepths( depth, readDepth( coord1 ), far );",
-
-				// DEPTH EXTRAPOLATION
-
-				"if ( far > 0 ) {",
-
-					"temp2 = compareDepths( readDepth( coord2 ), depth, far );",
-					"temp1 += ( 1.0 - temp1 ) * temp2;",
-
-				"}",
-
-				"return temp1;",
-
-			"}",
-
-			"void main() {",
-
-				"vec2 noise = rand( vUv );",
-				"float depth = readDepth( vUv );",
-
-				"float tt = clamp( depth, aoClamp, 1.0 );",
-
-				"float w = ( 1.0 / width )  / tt + ( noise.x * ( 1.0 - noise.x ) );",
-				"float h = ( 1.0 / height ) / tt + ( noise.y * ( 1.0 - noise.y ) );",
-
-				"float pw;",
-				"float ph;",
-
-				"float ao;",
-
-				"float dz = 1.0 / float( samples );",
-				"float z = 1.0 - dz / 2.0;",
-				"float l = 0.0;",
-
-				"for ( int i = 0; i <= samples; i ++ ) {",
-
-					"float r = sqrt( 1.0 - z );",
-
-					"pw = cos( l ) * r;",
-					"ph = sin( l ) * r;",
-					"ao += calcAO( depth, pw * w, ph * h );",
-					"z = z - dz;",
-					"l = l + DL;",
-
-				"}",
-
-				"ao /= float( samples );",
-				"ao = 1.0 - ao;",
-
-				"if ( fogEnabled ) {",
-
-					"ao = mix( ao, 1.0, doFog() );",
-
-				"}",
-
-				"vec3 color = texture2D( tDiffuse, vUv ).rgb;",
-
-				"vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );",
-				"float lum = dot( color.rgb, lumcoeff );",
-				"vec3 luminance = vec3( lum );",
-
-				"vec3 final = vec3( color * mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // mix( color * ao, white, luminance )
-
-				"if ( onlyAO ) {",
-
-					"final = vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // ambient occlusion only
-
-				"}",
-
-				"gl_FragColor = vec4( final, 1.0 );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Colorify shader
-	 ------------------------------------------------------------------------- */
-
-	'colorify': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			color:    { type: "c", value: new THREE.Color( 0xffffff ) }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform vec3 color;",
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vec4 texel = texture2D( tDiffuse, vUv );",
-
-				"vec3 luma = vec3( 0.299, 0.587, 0.114 );",
-				"float v = dot( texel.xyz, luma );",
-
-				"gl_FragColor = vec4( v * color, texel.w );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* -------------------------------------------------------------------------
-	//	Unpack RGBA depth shader
-	//	- show RGBA encoded depth as monochrome color
-	 ------------------------------------------------------------------------- */
-
-	'unpackDepthRGBA': {
-
-		uniforms: {
-
-			tDiffuse: { type: "t", value: 0, texture: null },
-			opacity:  { type: "f", value: 1.0 }
-
-		},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"uniform float opacity;",
-
-			"uniform sampler2D tDiffuse;",
-
-			"varying vec2 vUv;",
-
-			// RGBA depth
-
-			"float unpackDepth( const in vec4 rgba_depth ) {",
-
-				"const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
-				"float depth = dot( rgba_depth, bit_shift );",
-				"return depth;",
-
-			"}",
-
-			"void main() {",
-
-				"float depth = 1.0 - unpackDepth( texture2D( tDiffuse, vUv ) );",
-				"gl_FragColor = opacity * vec4( vec3( depth ), 1.0 );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	// METHODS
-
-	buildKernel: function( sigma ) {
-
-		// We lop off the sqrt(2 * pi) * sigma term, since we're going to normalize anyway.
-
-		function gauss( x, sigma ) {
-
-			return Math.exp( - ( x * x ) / ( 2.0 * sigma * sigma ) );
-
-		}
-
-		var i, values, sum, halfWidth, kMaxKernelSize = 25, kernelSize = 2 * Math.ceil( sigma * 3.0 ) + 1;
-
-		if ( kernelSize > kMaxKernelSize ) kernelSize = kMaxKernelSize;
-		halfWidth = ( kernelSize - 1 ) * 0.5
-
-		values = new Array( kernelSize );
-		sum = 0.0;
-		for ( i = 0; i < kernelSize; ++i ) {
-
-			values[ i ] = gauss( i - halfWidth, sigma );
-			sum += values[ i ];
-
-		}
-
-		// normalize the kernel
-
-		for ( i = 0; i < kernelSize; ++i ) values[ i ] /= sum;
-
-		return values;
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/ShaderSkin.js b/emperor/support_files/js/js/ShaderSkin.js
deleted file mode 100644
index 1858ff8..0000000
--- a/emperor/support_files/js/js/ShaderSkin.js
+++ /dev/null
@@ -1,752 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- */
-
-
-THREE.ShaderSkin = {
-
-	/* ------------------------------------------------------------------------------------------
-	//	Simple skin shader
-	//		- per-pixel Blinn-Phong diffuse term mixed with half-Lambert wrap-around term (per color component)
-	//		- physically based specular term (Kelemen/Szirmay-Kalos specular reflectance)
-	//
-	//		- diffuse map
-	//		- point and directional lights (use with "lights: true" material option)
-	//		- fog (use with "fog: true" material option)
-	//		- shadow maps
-	//
-	// ------------------------------------------------------------------------------------------ */
-
-	'skinSimple' : {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-			THREE.UniformsLib[ "shadowmap" ],
-
-			{
-
-			"tDiffuse"	: { type: "t", value: 0, texture: null },
-			"tBeckmann"	: { type: "t", value: 1, texture: null },
-
-			"uDiffuseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
-			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"uAmbientColor":  { type: "c", value: new THREE.Color( 0x050505 ) },
-			"uOpacity": 	  { type: "f", value: 1 },
-
-			"uRoughness": 	  		{ type: "f", value: 0.15 },
-			"uSpecularBrightness": 	{ type: "f", value: 0.75 },
-
-			"uWrapRGB":	{ type: "v3", value: new THREE.Vector3( 0.75, 0.375, 0.1875 ) }
-
-			}
-
-		] ),
-
-		fragmentShader: [
-
-			"uniform vec3 uAmbientColor;",
-			"uniform vec3 uDiffuseColor;",
-			"uniform vec3 uSpecularColor;",
-			"uniform float uOpacity;",
-
-			"uniform float uRoughness;",
-			"uniform float uSpecularBrightness;",
-
-			"uniform vec3 uWrapRGB;",
-
-			"uniform sampler2D tDiffuse;",
-			"uniform sampler2D tBeckmann;",
-
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"uniform vec3 ambientLightColor;",
-
-			"#if MAX_DIR_LIGHTS > 0",
-
-				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-			"#endif",
-
-			"#if MAX_POINT_LIGHTS > 0",
-
-				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-			"#endif",
-
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-
-			// Fresnel term
-
-			"float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",
-
-				"float base = 1.0 - dot( V, H );",
-				"float exponential = pow( base, 5.0 );",
-
-				"return exponential + F0 * ( 1.0 - exponential );",
-
-			"}",
-
-			// Kelemen/Szirmay-Kalos specular BRDF
-
-			"float KS_Skin_Specular( vec3 N,", 		// Bumped surface normal
-									"vec3 L,", 		// Points to light
-									"vec3 V,", 		// Points to eye
-									"float m,",  	// Roughness
-									"float rho_s", 	// Specular brightness
-									") {",
-
-				"float result = 0.0;",
-				"float ndotl = dot( N, L );",
-
-				"if( ndotl > 0.0 ) {",
-
-					"vec3 h = L + V;", // Unnormalized half-way vector
-					"vec3 H = normalize( h );",
-
-					"float ndoth = dot( N, H );",
-
-					"float PH = pow( 2.0 * texture2D( tBeckmann, vec2( ndoth, m ) ).x, 10.0 );",
-
-					"float F = fresnelReflectance( H, V, 0.028 );",
-					"float frSpec = max( PH * F / dot( h, h ), 0.0 );",
-
-					"result = ndotl * rho_s * frSpec;", // BRDF * dot(N,L) * rho_s
-
-				"}",
-
-				"return result;",
-
-			"}",
-
-			"void main() {",
-
-				"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
-
-				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
-				"colDiffuse.rgb *= colDiffuse.rgb;",
-
-				"gl_FragColor = gl_FragColor * colDiffuse;",
-
-				"vec3 normal = normalize( vNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
-
-				// point lights
-
-				"vec3 specularTotal = vec3( 0.0 );",
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"vec3 pointTotal = vec3( 0.0 );",
-
-					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-
-						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-						"lVector = normalize( lVector );",
-
-						"float pointDiffuseWeightFull = max( dot( normal, lVector ), 0.0 );",
-						"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, lVector ) + 0.5, 0.0 );",
-						"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), uWrapRGB );",
-
-						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
-
-						"pointTotal    += lDistance * uDiffuseColor * pointLightColor[ i ] * pointDiffuseWeight;",
-						"specularTotal += lDistance * uSpecularColor * pointLightColor[ i ] * pointSpecularWeight;",
-
-					"}",
-
-				"#endif",
-
-				// directional lights
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"vec3 dirTotal = vec3( 0.0 );",
-
-					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
-
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
-
-						"float dirDiffuseWeightFull = max( dot( normal, dirVector ), 0.0 );",
-						"float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
-						"vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), uWrapRGB );",
-
-						"float dirSpecularWeight =  KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
-
-						"dirTotal 	   += uDiffuseColor * directionalLightColor[ i ] * dirDiffuseWeight;",
-						"specularTotal += uSpecularColor * directionalLightColor[ i ] * dirSpecularWeight;",
-
-					"}",
-
-				"#endif",
-
-				// all lights contribution summation
-
-				"vec3 totalLight = vec3( 0.0 );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-					"totalLight += dirTotal;",
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-					"totalLight += pointTotal;",
-				"#endif",
-
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalLight + ambientLightColor * uAmbientColor ) + specularTotal;",
-
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n"),
-
-		vertexShader: [
-
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-
-			"void main() {",
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-				"vViewPosition = -mvPosition.xyz;",
-
-				"vNormal = normalMatrix * normal;",
-
-				"vUv = uv;",
-
-				"gl_Position = projectionMatrix * mvPosition;",
-
-				THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-			"}"
-
-		].join( "\n" )
-
-	},
-
-	/* ------------------------------------------------------------------------------------------
-	//	Skin shader
-	//		- Blinn-Phong diffuse term (using normal + diffuse maps)
-	//		- subsurface scattering approximation by four blur layers
-	//		- physically based specular term (Kelemen/Szirmay-Kalos specular reflectance)
-	//
-	//		- point and directional lights (use with "lights: true" material option)
-	//
-	//		- based on Nvidia Advanced Skin Rendering GDC 2007 presentation
-	//		  and GPU Gems 3 Chapter 14. Advanced Techniques for Realistic Real-Time Skin Rendering
-	//
-	//			http://developer.download.nvidia.com/presentations/2007/gdc/Advanced_Skin.pdf
-	//			http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html
-	// ------------------------------------------------------------------------------------------ */
-
-	'skin' : {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-
-			{
-
-			"passID": { type: "i", value: 0 },
-
-			"tDiffuse"	: { type: "t", value: 0, texture: null },
-			"tNormal"	: { type: "t", value: 1, texture: null },
-
-			"tBlur1"	: { type: "t", value: 2, texture: null },
-			"tBlur2"	: { type: "t", value: 3, texture: null },
-			"tBlur3"	: { type: "t", value: 4, texture: null },
-			"tBlur4"	: { type: "t", value: 5, texture: null },
-
-			"tBeckmann"	: { type: "t", value: 6, texture: null },
-
-			"uNormalScale": { type: "f", value: 1.0 },
-
-			"uDiffuseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
-			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"uAmbientColor":  { type: "c", value: new THREE.Color( 0x050505 ) },
-			"uOpacity": 	  { type: "f", value: 1 },
-
-			"uRoughness": 	  		{ type: "f", value: 0.15 },
-			"uSpecularBrightness": 	{ type: "f", value: 0.75 }
-
-			}
-
-		] ),
-
-		fragmentShader: [
-
-			"uniform vec3 uAmbientColor;",
-			"uniform vec3 uDiffuseColor;",
-			"uniform vec3 uSpecularColor;",
-			"uniform float uOpacity;",
-
-			"uniform float uRoughness;",
-			"uniform float uSpecularBrightness;",
-
-			"uniform int passID;",
-
-			"uniform sampler2D tDiffuse;",
-			"uniform sampler2D tNormal;",
-
-			"uniform sampler2D tBlur1;",
-			"uniform sampler2D tBlur2;",
-			"uniform sampler2D tBlur3;",
-			"uniform sampler2D tBlur4;",
-
-			"uniform sampler2D tBeckmann;",
-
-			"uniform float uNormalScale;",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"uniform vec3 ambientLightColor;",
-
-			"#if MAX_DIR_LIGHTS > 0",
-				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-			"#endif",
-
-			"#if MAX_POINT_LIGHTS > 0",
-				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
-			"#endif",
-
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-
-			"float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",
-
-				"float base = 1.0 - dot( V, H );",
-				"float exponential = pow( base, 5.0 );",
-
-				"return exponential + F0 * ( 1.0 - exponential );",
-
-			"}",
-
-			// Kelemen/Szirmay-Kalos specular BRDF
-
-			"float KS_Skin_Specular( vec3 N,", 		// Bumped surface normal
-									"vec3 L,", 		// Points to light
-									"vec3 V,", 		// Points to eye
-									"float m,",  	// Roughness
-									"float rho_s", 	// Specular brightness
-									") {",
-
-				"float result = 0.0;",
-				"float ndotl = dot( N, L );",
-
-				"if( ndotl > 0.0 ) {",
-
-					"vec3 h = L + V;", // Unnormalized half-way vector
-					"vec3 H = normalize( h );",
-
-					"float ndoth = dot( N, H );",
-
-					"float PH = pow( 2.0 * texture2D( tBeckmann, vec2( ndoth, m ) ).x, 10.0 );",
-					"float F = fresnelReflectance( H, V, 0.028 );",
-					"float frSpec = max( PH * F / dot( h, h ), 0.0 );",
-
-					"result = ndotl * rho_s * frSpec;", // BRDF * dot(N,L) * rho_s
-
-				"}",
-
-				"return result;",
-
-			"}",
-
-			"void main() {",
-
-				"gl_FragColor = vec4( 1.0 );",
-
-				"vec4 mColor = vec4( uDiffuseColor, uOpacity );",
-				"vec4 mSpecular = vec4( uSpecularColor, uOpacity );",
-
-				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
-				"normalTex.xy *= uNormalScale;",
-				"normalTex = normalize( normalTex );",
-
-				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
-				"colDiffuse *= colDiffuse;",
-
-				"gl_FragColor = gl_FragColor * colDiffuse;",
-
-				"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
-				"vec3 finalNormal = tsb * normalTex;",
-
-				"vec3 normal = normalize( finalNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
-
-				// point lights
-
-				"vec3 specularTotal = vec3( 0.0 );",
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"vec4 pointTotal = vec4( vec3( 0.0 ), 1.0 );",
-
-					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-						"vec3 pointVector = normalize( vPointLight[ i ].xyz );",
-						"float pointDistance = vPointLight[ i ].w;",
-
-						"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
-
-						"pointTotal  += pointDistance * vec4( pointLightColor[ i ], 1.0 ) * ( mColor * pointDiffuseWeight );",
-
-						"if ( passID == 1 )",
-							"specularTotal += pointDistance * mSpecular.xyz * pointLightColor[ i ] * KS_Skin_Specular( normal, pointVector, viewPosition, uRoughness, uSpecularBrightness );",
-
-					"}",
-
-				"#endif",
-
-				// directional lights
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"vec4 dirTotal = vec4( vec3( 0.0 ), 1.0 );",
-
-					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
-
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
-
-						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
-
-						"dirTotal  += vec4( directionalLightColor[ i ], 1.0 ) * ( mColor * dirDiffuseWeight );",
-
-						"if ( passID == 1 )",
-							"specularTotal += mSpecular.xyz * directionalLightColor[ i ] * KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
-
-					"}",
-
-				"#endif",
-
-				// all lights contribution summation
-
-				"vec4 totalLight = vec4( vec3( 0.0 ), uOpacity );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-					"totalLight += dirTotal;",
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-					"totalLight += pointTotal;",
-				"#endif",
-
-				"gl_FragColor = gl_FragColor * totalLight;",
-
-				"if ( passID == 0 ) {",
-
-					"gl_FragColor = vec4( sqrt( gl_FragColor.xyz ), gl_FragColor.w );",
-
-				"} else if ( passID == 1 ) {",
-
-					//"#define VERSION1",
-
-					"#ifdef VERSION1",
-
-						"vec3 nonblurColor = sqrt( gl_FragColor.xyz );",
-
-					"#else",
-
-						"vec3 nonblurColor = gl_FragColor.xyz;",
-
-					"#endif",
-
-					"vec3 blur1Color = texture2D( tBlur1, vUv ).xyz;",
-					"vec3 blur2Color = texture2D( tBlur2, vUv ).xyz;",
-					"vec3 blur3Color = texture2D( tBlur3, vUv ).xyz;",
-					"vec3 blur4Color = texture2D( tBlur4, vUv ).xyz;",
-
-
-					//"gl_FragColor = vec4( blur1Color, gl_FragColor.w );",
-
-					//"gl_FragColor = vec4( vec3( 0.22, 0.5, 0.7 ) * nonblurColor + vec3( 0.2, 0.5, 0.3 ) * blur1Color + vec3( 0.58, 0.0, 0.0 ) * blur2Color, gl_FragColor.w );",
-
-					//"gl_FragColor = vec4( vec3( 0.25, 0.6, 0.8 ) * nonblurColor + vec3( 0.15, 0.25, 0.2 ) * blur1Color + vec3( 0.15, 0.15, 0.0 ) * blur2Color + vec3( 0.45, 0.0, 0.0 ) * blur3Color, gl_FragColor.w );",
-
-
-					"gl_FragColor = vec4( vec3( 0.22,  0.437, 0.635 ) * nonblurColor + ",
-										 "vec3( 0.101, 0.355, 0.365 ) * blur1Color + ",
-										 "vec3( 0.119, 0.208, 0.0 )   * blur2Color + ",
-										 "vec3( 0.114, 0.0,   0.0 )   * blur3Color + ",
-										 "vec3( 0.444, 0.0,   0.0 )   * blur4Color",
-										 ", gl_FragColor.w );",
-
-					"gl_FragColor.xyz *= pow( colDiffuse.xyz, vec3( 0.5 ) );",
-
-					"gl_FragColor.xyz += ambientLightColor * uAmbientColor * colDiffuse.xyz + specularTotal;",
-
-					"#ifndef VERSION1",
-
-						"gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
-
-					"#endif",
-
-				"}",
-
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n"),
-
-		vertexShader: [
-
-			"attribute vec4 tangent;",
-
-			"#ifdef VERTEX_TEXTURES",
-
-				"uniform sampler2D tDisplacement;",
-				"uniform float uDisplacementScale;",
-				"uniform float uDisplacementBias;",
-
-			"#endif",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"#if MAX_POINT_LIGHTS > 0",
-
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
-
-			"#endif",
-
-			"varying vec3 vViewPosition;",
-
-			"void main() {",
-
-				"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-				"vViewPosition = -mvPosition.xyz;",
-
-				"vNormal = normalize( normalMatrix * normal );",
-
-				// tangent and binormal vectors
-
-				"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
-				"vBinormal = normalize( vBinormal );",
-
-				"vUv = uv;",
-
-				// point lights
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-
-						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-						"lVector = normalize( lVector );",
-
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
-
-					"}",
-
-				"#endif",
-
-				// displacement mapping
-
-				"#ifdef VERTEX_TEXTURES",
-
-					"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
-					"float df = uDisplacementScale * dv.x + uDisplacementBias;",
-					"vec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;",
-					"gl_Position = projectionMatrix * displacedPosition;",
-
-				"#else",
-
-					"gl_Position = projectionMatrix * mvPosition;",
-
-				"#endif",
-
-			"}"
-
-		].join("\n"),
-
-		vertexShaderUV: [
-
-			"attribute vec4 tangent;",
-
-			"#ifdef VERTEX_TEXTURES",
-
-				"uniform sampler2D tDisplacement;",
-				"uniform float uDisplacementScale;",
-				"uniform float uDisplacementBias;",
-
-			"#endif",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"#if MAX_POINT_LIGHTS > 0",
-
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
-
-			"#endif",
-
-			"varying vec3 vViewPosition;",
-
-			"void main() {",
-
-				"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-				"vViewPosition = -mvPosition.xyz;",
-
-				"vNormal = normalize( normalMatrix * normal );",
-
-				// tangent and binormal vectors
-
-				"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
-				"vBinormal = normalize( vBinormal );",
-
-				"vUv = uv;",
-
-				// point lights
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-
-						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-						"lVector = normalize( lVector );",
-
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
-
-					"}",
-
-				"#endif",
-
-				"gl_Position = vec4( uv.x * 2.0 - 1.0, uv.y * 2.0 - 1.0, 0.0, 1.0 );",
-
-			"}"
-
-		].join("\n")
-
-	},
-
-	/* ------------------------------------------------------------------------------------------
-	// Beckmann distribution function
-	//	- to be used in specular term of skin shader
-	//	- render a screen-aligned quad to precompute a 512 x 512 texture
-	//
-	//		- from http://developer.nvidia.com/node/171
-	 ------------------------------------------------------------------------------------------ */
-
-	"beckmann" : {
-
-		uniforms: {},
-
-		vertexShader: [
-
-			"varying vec2 vUv;",
-
-			"void main() {",
-
-				"vUv = vec2( uv.x, 1.0 - uv.y );",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
-			"}"
-
-		].join("\n"),
-
-		fragmentShader: [
-
-			"varying vec2 vUv;",
-
-			"float PHBeckmann( float ndoth, float m ) {",
-
-				"float alpha = acos( ndoth );",
-				"float ta = tan( alpha );",
-
-				"float val = 1.0 / ( m * m * pow( ndoth, 4.0 ) ) * exp( -( ta * ta ) / ( m * m ) );",
-				"return val;",
-
-			"}",
-
-			"float KSTextureCompute( vec2 tex ) {",
-
-				// Scale the value to fit within [0,1] � invert upon lookup.
-
-				"return 0.5 * pow( PHBeckmann( tex.x, tex.y ), 0.1 );",
-
-			"}",
-
-			"void main() {",
-
-				"float x = KSTextureCompute( vUv );",
-
-				"gl_FragColor = vec4( x, x, x, 1.0 );",
-
-			"}"
-
-		].join("\n")
-
-	}
-
-};
\ No newline at end of file
diff --git a/emperor/support_files/js/js/ShaderTerrain.js b/emperor/support_files/js/js/ShaderTerrain.js
deleted file mode 100644
index ff147a7..0000000
--- a/emperor/support_files/js/js/ShaderTerrain.js
+++ /dev/null
@@ -1,306 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- */
-
-THREE.ShaderTerrain = {
-
-	/* -------------------------------------------------------------------------
-	//	Dynamic terrain shader
-	//		- Blinn-Phong
-	//		- height + normal + diffuse1 + diffuse2 + specular + detail maps
-	//		- point and directional lights (use with "lights: true" material option)
-	 ------------------------------------------------------------------------- */
-
-	'terrain' : {
-
-		uniforms: THREE.UniformsUtils.merge( [
-
-			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "lights" ],
-
-			{
-
-			"enableDiffuse1"  : { type: "i", value: 0 },
-			"enableDiffuse2"  : { type: "i", value: 0 },
-			"enableSpecular"  : { type: "i", value: 0 },
-			"enableReflection": { type: "i", value: 0 },
-
-			"tDiffuse1"	   : { type: "t", value: 0, texture: null },
-			"tDiffuse2"	   : { type: "t", value: 1, texture: null },
-			"tDetail"	   : { type: "t", value: 2, texture: null },
-			"tNormal"	   : { type: "t", value: 3, texture: null },
-			"tSpecular"	   : { type: "t", value: 4, texture: null },
-			"tDisplacement": { type: "t", value: 5, texture: null },
-
-			"uNormalScale": { type: "f", value: 1.0 },
-
-			"uDisplacementBias": { type: "f", value: 0.0 },
-			"uDisplacementScale": { type: "f", value: 1.0 },
-
-			"uDiffuseColor": { type: "c", value: new THREE.Color( 0xeeeeee ) },
-			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"uAmbientColor": { type: "c", value: new THREE.Color( 0x050505 ) },
-			"uShininess": { type: "f", value: 30 },
-			"uOpacity": { type: "f", value: 1 },
-
-			"uRepeatBase"    : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
-			"uRepeatOverlay" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
-
-			"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }
-
-			}
-
-		] ),
-
-		fragmentShader: [
-
-			"uniform vec3 uAmbientColor;",
-			"uniform vec3 uDiffuseColor;",
-			"uniform vec3 uSpecularColor;",
-			"uniform float uShininess;",
-			"uniform float uOpacity;",
-
-			"uniform bool enableDiffuse1;",
-			"uniform bool enableDiffuse2;",
-			"uniform bool enableSpecular;",
-
-			"uniform sampler2D tDiffuse1;",
-			"uniform sampler2D tDiffuse2;",
-			"uniform sampler2D tDetail;",
-			"uniform sampler2D tNormal;",
-			"uniform sampler2D tSpecular;",
-			"uniform sampler2D tDisplacement;",
-
-			"uniform float uNormalScale;",
-
-			"uniform vec2 uRepeatOverlay;",
-			"uniform vec2 uRepeatBase;",
-
-			"uniform vec2 uOffset;",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"uniform vec3 ambientLightColor;",
-
-			"#if MAX_DIR_LIGHTS > 0",
-				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-			"#endif",
-
-			"#if MAX_POINT_LIGHTS > 0",
-				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-			"#endif",
-
-			"varying vec3 vViewPosition;",
-
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-
-			"void main() {",
-
-				"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
-
-				"vec3 specularTex = vec3( 1.0 );",
-
-				"vec2 uvOverlay = uRepeatOverlay * vUv + uOffset;",
-				"vec2 uvBase = uRepeatBase * vUv;",
-
-				"vec3 normalTex = texture2D( tDetail, uvOverlay ).xyz * 2.0 - 1.0;",
-				"normalTex.xy *= uNormalScale;",
-				"normalTex = normalize( normalTex );",
-
-				"if( enableDiffuse1 && enableDiffuse2 ) {",
-
-					"vec4 colDiffuse1 = texture2D( tDiffuse1, uvOverlay );",
-					"vec4 colDiffuse2 = texture2D( tDiffuse2, uvOverlay );",
-
-					"#ifdef GAMMA_INPUT",
-
-						"colDiffuse1.xyz *= colDiffuse1.xyz;",
-						"colDiffuse2.xyz *= colDiffuse2.xyz;",
-
-					"#endif",
-
-					"gl_FragColor = gl_FragColor * mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );",
-
-				" } else if( enableDiffuse1 ) {",
-
-					"gl_FragColor = gl_FragColor * texture2D( tDiffuse1, uvOverlay );",
-
-				"} else if( enableDiffuse2 ) {",
-
-					"gl_FragColor = gl_FragColor * texture2D( tDiffuse2, uvOverlay );",
-
-				"}",
-
-				"if( enableSpecular )",
-					"specularTex = texture2D( tSpecular, uvOverlay ).xyz;",
-
-				"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
-				"vec3 finalNormal = tsb * normalTex;",
-
-				"vec3 normal = normalize( finalNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
-
-				// point lights
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"vec3 pointDiffuse = vec3( 0.0 );",
-					"vec3 pointSpecular = vec3( 0.0 );",
-
-					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-						"float lDistance = 1.0;",
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-						"lVector = normalize( lVector );",
-
-						"vec3 pointHalfVector = normalize( lVector + viewPosition );",
-						"float pointDistance = lDistance;",
-
-						"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
-						"float pointDiffuseWeight = max( dot( normal, lVector ), 0.0 );",
-
-						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",
-
-						"pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",
-						"pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;",
-
-					"}",
-
-				"#endif",
-
-				// directional lights
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"vec3 dirDiffuse = vec3( 0.0 );",
-					"vec3 dirSpecular = vec3( 0.0 );",
-
-					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
-
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
-						"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
-
-						"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
-						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
-
-						"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",
-
-						"dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",
-						"dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;",
-
-					"}",
-
-				"#endif",
-
-				// all lights contribution summation
-
-				"vec3 totalDiffuse = vec3( 0.0 );",
-				"vec3 totalSpecular = vec3( 0.0 );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"totalDiffuse += dirDiffuse;",
-					"totalSpecular += dirSpecular;",
-
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"totalDiffuse += pointDiffuse;",
-					"totalSpecular += pointSpecular;",
-
-				"#endif",
-
-				//"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;",
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );",
-
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-			"}"
-
-		].join("\n"),
-
-		vertexShader: [
-
-			"attribute vec4 tangent;",
-
-			"uniform vec2 uRepeatBase;",
-
-			"uniform sampler2D tNormal;",
-
-			"#ifdef VERTEX_TEXTURES",
-
-				"uniform sampler2D tDisplacement;",
-				"uniform float uDisplacementScale;",
-				"uniform float uDisplacementBias;",
-
-			"#endif",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
-			"varying vec3 vNormal;",
-			"varying vec2 vUv;",
-
-			"varying vec3 vViewPosition;",
-
-			"void main() {",
-
-				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-				"vViewPosition = -mvPosition.xyz;",
-
-				"vNormal = normalize( normalMatrix * normal );",
-
-				// tangent and binormal vectors
-
-				"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
-				"vBinormal = normalize( vBinormal );",
-
-				// texture coordinates
-
-				"vUv = uv;",
-
-				"vec2 uvBase = uv * uRepeatBase;",
-
-				// displacement mapping
-
-				"#ifdef VERTEX_TEXTURES",
-
-					"vec3 dv = texture2D( tDisplacement, uvBase ).xyz;",
-					"float df = uDisplacementScale * dv.x + uDisplacementBias;",
-					"vec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;",
-					"gl_Position = projectionMatrix * displacedPosition;",
-
-				"#else",
-
-					"gl_Position = projectionMatrix * mvPosition;",
-
-				"#endif",
-
-				"vec3 normalTex = texture2D( tNormal, uvBase ).xyz * 2.0 - 1.0;",
-				"vNormal = normalMatrix * normalTex;",
-
-			"}"
-
-		].join("\n")
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/SimplexNoise.js b/emperor/support_files/js/js/SimplexNoise.js
deleted file mode 100644
index 5f85487..0000000
--- a/emperor/support_files/js/js/SimplexNoise.js
+++ /dev/null
@@ -1,316 +0,0 @@
-// Ported from Stefan Gustavson's java implementation
-// http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
-// Read Stefan's excellent paper for details on how this code works.
-//
-// Sean McCullough banksean at gmail.com
-//
-// Added 4D noise
-// Joshua Koo zz85nus at gmail.com 
-
-/**
- * You can pass in a random number generator object if you like.
- * It is assumed to have a random() method.
- */
-var SimplexNoise = function(r) {
-	if (r == undefined) r = Math;
-  this.grad3 = [[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0], 
-                                 [1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1], 
-                                 [0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]]; 
-
-  this.grad4 = [[0,1,1,1], [0,1,1,-1], [0,1,-1,1], [0,1,-1,-1],
-	     [0,-1,1,1], [0,-1,1,-1], [0,-1,-1,1], [0,-1,-1,-1],
-	     [1,0,1,1], [1,0,1,-1], [1,0,-1,1], [1,0,-1,-1],
-	     [-1,0,1,1], [-1,0,1,-1], [-1,0,-1,1], [-1,0,-1,-1],
-	     [1,1,0,1], [1,1,0,-1], [1,-1,0,1], [1,-1,0,-1],
-	     [-1,1,0,1], [-1,1,0,-1], [-1,-1,0,1], [-1,-1,0,-1],
-	     [1,1,1,0], [1,1,-1,0], [1,-1,1,0], [1,-1,-1,0],
-	     [-1,1,1,0], [-1,1,-1,0], [-1,-1,1,0], [-1,-1,-1,0]];
-
-  this.p = [];
-  for (var i=0; i<256; i++) {
-	  this.p[i] = Math.floor(r.random()*256);
-  }
-  // To remove the need for index wrapping, double the permutation table length 
-  this.perm = []; 
-  for(var i=0; i<512; i++) {
-		this.perm[i]=this.p[i & 255];
-	} 
-
-  // A lookup table to traverse the simplex around a given point in 4D. 
-  // Details can be found where this table is used, in the 4D noise method. 
-  this.simplex = [ 
-    [0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0], 
-    [0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0], 
-    [0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], 
-    [1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0], 
-    [1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0], 
-    [0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], 
-    [2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0], 
-    [2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]]; 
-};
-
-SimplexNoise.prototype.dot = function(g, x, y) { 
-	return g[0]*x + g[1]*y;
-};
-
-SimplexNoise.prototype.noise = function(xin, yin) { 
-  var n0, n1, n2; // Noise contributions from the three corners 
-  // Skew the input space to determine which simplex cell we're in 
-  var F2 = 0.5*(Math.sqrt(3.0)-1.0); 
-  var s = (xin+yin)*F2; // Hairy factor for 2D 
-  var i = Math.floor(xin+s); 
-  var j = Math.floor(yin+s); 
-  var G2 = (3.0-Math.sqrt(3.0))/6.0; 
-  var t = (i+j)*G2; 
-  var X0 = i-t; // Unskew the cell origin back to (x,y) space 
-  var Y0 = j-t; 
-  var x0 = xin-X0; // The x,y distances from the cell origin 
-  var y0 = yin-Y0; 
-  // For the 2D case, the simplex shape is an equilateral triangle. 
-  // Determine which simplex we are in. 
-  var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 
-  if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1) 
-  else {i1=0; j1=1;}      // upper triangle, YX order: (0,0)->(0,1)->(1,1) 
-  // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 
-  // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 
-  // c = (3-sqrt(3))/6 
-  var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 
-  var y1 = y0 - j1 + G2; 
-  var x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords 
-  var y2 = y0 - 1.0 + 2.0 * G2; 
-  // Work out the hashed gradient indices of the three simplex corners 
-  var ii = i & 255; 
-  var jj = j & 255; 
-  var gi0 = this.perm[ii+this.perm[jj]] % 12; 
-  var gi1 = this.perm[ii+i1+this.perm[jj+j1]] % 12; 
-  var gi2 = this.perm[ii+1+this.perm[jj+1]] % 12; 
-  // Calculate the contribution from the three corners 
-  var t0 = 0.5 - x0*x0-y0*y0; 
-  if(t0<0) n0 = 0.0; 
-  else { 
-    t0 *= t0; 
-    n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0);  // (x,y) of grad3 used for 2D gradient 
-  } 
-  var t1 = 0.5 - x1*x1-y1*y1; 
-  if(t1<0) n1 = 0.0; 
-  else { 
-    t1 *= t1; 
-    n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1); 
-  }
-  var t2 = 0.5 - x2*x2-y2*y2; 
-  if(t2<0) n2 = 0.0; 
-  else { 
-    t2 *= t2; 
-    n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2); 
-  } 
-  // Add contributions from each corner to get the final noise value. 
-  // The result is scaled to return values in the interval [-1,1]. 
-  return 70.0 * (n0 + n1 + n2); 
-};
-
-// 3D simplex noise 
-SimplexNoise.prototype.noise3d = function(xin, yin, zin) { 
-  var n0, n1, n2, n3; // Noise contributions from the four corners 
-  // Skew the input space to determine which simplex cell we're in 
-  var F3 = 1.0/3.0; 
-  var s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D 
-  var i = Math.floor(xin+s); 
-  var j = Math.floor(yin+s); 
-  var k = Math.floor(zin+s); 
-  var G3 = 1.0/6.0; // Very nice and simple unskew factor, too 
-  var t = (i+j+k)*G3; 
-  var X0 = i-t; // Unskew the cell origin back to (x,y,z) space 
-  var Y0 = j-t; 
-  var Z0 = k-t; 
-  var x0 = xin-X0; // The x,y,z distances from the cell origin 
-  var y0 = yin-Y0; 
-  var z0 = zin-Z0; 
-  // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 
-  // Determine which simplex we are in. 
-  var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 
-  var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 
-  if(x0>=y0) { 
-    if(y0>=z0) 
-      { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order 
-      else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order 
-      else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order 
-    } 
-  else { // x0<y0 
-    if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order 
-    else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order 
-    else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order 
-  } 
-  // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), 
-  // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and 
-  // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where 
-  // c = 1/6.
-  var x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords 
-  var y1 = y0 - j1 + G3; 
-  var z1 = z0 - k1 + G3; 
-  var x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords 
-  var y2 = y0 - j2 + 2.0*G3; 
-  var z2 = z0 - k2 + 2.0*G3; 
-  var x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords 
-  var y3 = y0 - 1.0 + 3.0*G3; 
-  var z3 = z0 - 1.0 + 3.0*G3; 
-  // Work out the hashed gradient indices of the four simplex corners 
-  var ii = i & 255; 
-  var jj = j & 255; 
-  var kk = k & 255; 
-  var gi0 = this.perm[ii+this.perm[jj+this.perm[kk]]] % 12; 
-  var gi1 = this.perm[ii+i1+this.perm[jj+j1+this.perm[kk+k1]]] % 12; 
-  var gi2 = this.perm[ii+i2+this.perm[jj+j2+this.perm[kk+k2]]] % 12; 
-  var gi3 = this.perm[ii+1+this.perm[jj+1+this.perm[kk+1]]] % 12; 
-  // Calculate the contribution from the four corners 
-  var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; 
-  if(t0<0) n0 = 0.0; 
-  else { 
-    t0 *= t0; 
-    n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0, z0); 
-  }
-  var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; 
-  if(t1<0) n1 = 0.0; 
-  else { 
-    t1 *= t1; 
-    n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1, z1); 
-  } 
-  var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; 
-  if(t2<0) n2 = 0.0; 
-  else { 
-    t2 *= t2; 
-    n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2, z2); 
-  } 
-  var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; 
-  if(t3<0) n3 = 0.0; 
-  else { 
-    t3 *= t3; 
-    n3 = t3 * t3 * this.dot(this.grad3[gi3], x3, y3, z3); 
-  } 
-  // Add contributions from each corner to get the final noise value. 
-  // The result is scaled to stay just inside [-1,1] 
-  return 32.0*(n0 + n1 + n2 + n3); 
-};
-
-// 4D simplex noise
-SimplexNoise.prototype.noise4d = function( x, y, z, w ) {
-	// For faster and easier lookups
-	var grad4 = this.grad4;
-	var simplex = this.simplex;
-	var perm = this.perm;
-	
-   // The skewing and unskewing factors are hairy again for the 4D case
-   var F4 = (Math.sqrt(5.0)-1.0)/4.0;
-   var G4 = (5.0-Math.sqrt(5.0))/20.0;
-   var n0, n1, n2, n3, n4; // Noise contributions from the five corners
-   // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
-   var s = (x + y + z + w) * F4; // Factor for 4D skewing
-   var i = Math.floor(x + s);
-   var j = Math.floor(y + s);
-   var k = Math.floor(z + s);
-   var l = Math.floor(w + s);
-   var t = (i + j + k + l) * G4; // Factor for 4D unskewing
-   var X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
-   var Y0 = j - t;
-   var Z0 = k - t;
-   var W0 = l - t;
-   var x0 = x - X0;  // The x,y,z,w distances from the cell origin
-   var y0 = y - Y0;
-   var z0 = z - Z0;
-   var w0 = w - W0;
-
-   // For the 4D case, the simplex is a 4D shape I won't even try to describe.
-   // To find out which of the 24 possible simplices we're in, we need to
-   // determine the magnitude ordering of x0, y0, z0 and w0.
-   // The method below is a good way of finding the ordering of x,y,z,w and
-   // then find the correct traversal order for the simplex we’re in.
-   // First, six pair-wise comparisons are performed between each possible pair
-   // of the four coordinates, and the results are used to add up binary bits
-   // for an integer index.
-   var c1 = (x0 > y0) ? 32 : 0;
-   var c2 = (x0 > z0) ? 16 : 0;
-   var c3 = (y0 > z0) ? 8 : 0;
-   var c4 = (x0 > w0) ? 4 : 0;
-   var c5 = (y0 > w0) ? 2 : 0;
-   var c6 = (z0 > w0) ? 1 : 0;
-   var c = c1 + c2 + c3 + c4 + c5 + c6;
-   var i1, j1, k1, l1; // The integer offsets for the second simplex corner
-   var i2, j2, k2, l2; // The integer offsets for the third simplex corner
-   var i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
-   // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
-   // Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
-   // impossible. Only the 24 indices which have non-zero entries make any sense.
-   // We use a thresholding to set the coordinates in turn from the largest magnitude.
-   // The number 3 in the "simplex" array is at the position of the largest coordinate.
-   i1 = simplex[c][0]>=3 ? 1 : 0;
-   j1 = simplex[c][1]>=3 ? 1 : 0;
-   k1 = simplex[c][2]>=3 ? 1 : 0;
-   l1 = simplex[c][3]>=3 ? 1 : 0;
-   // The number 2 in the "simplex" array is at the second largest coordinate.
-   i2 = simplex[c][0]>=2 ? 1 : 0;
-   j2 = simplex[c][1]>=2 ? 1 : 0;    k2 = simplex[c][2]>=2 ? 1 : 0;
-   l2 = simplex[c][3]>=2 ? 1 : 0;
-   // The number 1 in the "simplex" array is at the second smallest coordinate.
-   i3 = simplex[c][0]>=1 ? 1 : 0;
-   j3 = simplex[c][1]>=1 ? 1 : 0;
-   k3 = simplex[c][2]>=1 ? 1 : 0;
-   l3 = simplex[c][3]>=1 ? 1 : 0;
-   // The fifth corner has all coordinate offsets = 1, so no need to look that up.
-   var x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
-   var y1 = y0 - j1 + G4;
-   var z1 = z0 - k1 + G4;
-   var w1 = w0 - l1 + G4;
-   var x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords
-   var y2 = y0 - j2 + 2.0*G4;
-   var z2 = z0 - k2 + 2.0*G4;
-   var w2 = w0 - l2 + 2.0*G4;
-   var x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords
-   var y3 = y0 - j3 + 3.0*G4;
-   var z3 = z0 - k3 + 3.0*G4;
-   var w3 = w0 - l3 + 3.0*G4;
-   var x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords
-   var y4 = y0 - 1.0 + 4.0*G4;
-   var z4 = z0 - 1.0 + 4.0*G4;
-   var w4 = w0 - 1.0 + 4.0*G4;
-   // Work out the hashed gradient indices of the five simplex corners
-   var ii = i & 255;
-   var jj = j & 255;
-   var kk = k & 255;
-   var ll = l & 255;
-   var gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32;
-   var gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32;
-   var gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32;
-   var gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32;
-   var gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32;
-   // Calculate the contribution from the five corners
-   var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;
-   if(t0<0) n0 = 0.0;
-   else {
-     t0 *= t0;
-     n0 = t0 * t0 * this.dot(grad4[gi0], x0, y0, z0, w0);
-   }
-  var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;
-   if(t1<0) n1 = 0.0;
-   else {
-     t1 *= t1;
-     n1 = t1 * t1 * this.dot(grad4[gi1], x1, y1, z1, w1);
-   }
-  var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;
-   if(t2<0) n2 = 0.0;
-   else {
-     t2 *= t2;
-     n2 = t2 * t2 * this.dot(grad4[gi2], x2, y2, z2, w2);
-   }   var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;
-   if(t3<0) n3 = 0.0;
-   else {
-     t3 *= t3;
-     n3 = t3 * t3 * this.dot(grad4[gi3], x3, y3, z3, w3);
-   }
-  var t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;
-   if(t4<0) n4 = 0.0;
-   else {
-     t4 *= t4;
-     n4 = t4 * t4 * this.dot(grad4[gi4], x4, y4, z4, w4);
-   }
-   // Sum up and scale the result to cover the range [-1,1]
-   return 27.0 * (n0 + n1 + n2 + n3 + n4);
-};
diff --git a/emperor/support_files/js/js/Sparks.js b/emperor/support_files/js/js/Sparks.js
deleted file mode 100644
index 3b63994..0000000
--- a/emperor/support_files/js/js/Sparks.js
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * @author zz85 (http://github.com/zz85 http://www.lab4games.net/zz85/blog)
- *
- * a simple to use javascript 3d particles system inspired by FliNT and Stardust
- * created with TWEEN.js and THREE.js
- *
- * for feature requests or bugs, please visit https://github.com/zz85/sparks.js
- *
- * licensed under the MIT license 
- */
-
-var SPARKS = {};
-
-/********************************
-* Emitter Class
-*
-*   Creates and Manages Particles
-*********************************/
-
-SPARKS.Emitter = function (counter) {
-    
-    this._counter = counter ? counter : new SPARKS.SteadyCounter(10); // provides number of particles to produce
-    
-    this._particles = [];
-    
-    
-    this._initializers = []; // use for creation of particles
-    this._actions = [];     // uses action to update particles
-    this._activities = [];  //  not supported yet
-        
-    this._handlers = [];
-    
-    this.callbacks = {};
-};
-
-
-SPARKS.Emitter.prototype = {
-	
-	_TIMESTEP: 15,
-	_timer: null,
-	_lastTime: null,
-	_timerStep: 10,
-	_velocityVerlet: true,
-	
-	// run its built in timer / stepping
-	start: function() {
-		this._lastTime = Date.now();
-		this._timer = setTimeout(this.step, this._timerStep, this);
-		this._isRunning = true;
-	},
-	
-	stop: function() {
-		this._isRunning = false;
-		clearTimeout(this._timer);
-	},
-	
-	isRunning: function() {
-		return this._isRunning & true;
-	},
-	
-	// Step gets called upon by the engine
-	// but attempts to call update() on a regular basics
-	// This method is also described in http://gameclosure.com/2011/04/11/deterministic-delta-tee-in-js-games/
-	step: function(emitter) {
-		
-		var time = Date.now();
-		var elapsed = time - emitter._lastTime;
-	   	
-		if (!this._velocityVerlet) {
-			// if elapsed is way higher than time step, (usually after switching tabs, or excution cached in ff)
-			// we will drop cycles. perhaps set to a limit of 10 or something?
-			var maxBlock = emitter._TIMESTEP * 20;
-			
-			if (elapsed >= maxBlock) {
-				//console.log('warning: sparks.js is fast fowarding engine, skipping steps', elapsed / emitter._TIMESTEP);
-				//emitter.update( (elapsed - maxBlock) / 1000);
-				elapsed = maxBlock;
-			}
-		
-			while(elapsed >= emitter._TIMESTEP) {
-				emitter.update(emitter._TIMESTEP / 1000);
-				elapsed -= emitter._TIMESTEP;
-			}
-			emitter._lastTime = time - elapsed;
-			
-		} else {
-			emitter.update(elapsed/1000);
-			emitter._lastTime = time;
-		}
-		
-		
-		
-		if (emitter._isRunning)
-		setTimeout(emitter.step, emitter._timerStep, emitter);
-		
-	},
-
-
-	// Update particle engine in seconds, not milliseconds
-    update: function(time) {
-		
-        var len = this._counter.updateEmitter( this, time );
-        
-        // Create particles
-        for( i = 0; i < len; i++ ) {
-            this.createParticle();
-        }
-        
-        // Update activities
-        len = this._activities.length;
-        for ( i = 0; i < len; i++ )
-        {
-            this_.activities[i].update( this, time );
-        }
-        
-        
-        len = this._actions.length;
-        var action;
-        var len2 = this._particles.length;
-        
-        for( j = 0; j < len; j++ )
-        {
-            action = this._actions[j];
-            for ( i = 0; i < len2; ++i )
-            {
-                particle = this._particles[i];
-                action.update( this, particle, time );
-            }
-        }
-        
-        
-        // remove dead particles
-        for ( i = len2; i--; )
-        {
-            particle = this._particles[i];
-            if ( particle.isDead )
-            {
-                //particle = 
-				this._particles.splice( i, 1 );
-                this.dispatchEvent("dead", particle);
-				SPARKS.VectorPool.release(particle.position); //
-				SPARKS.VectorPool.release(particle.velocity);
-                
-            } else {
-                this.dispatchEvent("updated", particle);
-            }
-        }
-        
-		this.dispatchEvent("loopUpdated");
-		
-    },
-    
-    createParticle: function() {
-        var particle = new SPARKS.Particle();
-        // In future, use a Particle Factory
-        var len = this._initializers.length, i;
-
-        for ( i = 0; i < len; i++ ) {
-            this._initializers[i].initialize( this, particle );
-        }
-        
-        this._particles.push( particle );
-        
-        this.dispatchEvent("created", particle); // ParticleCreated
-        
-        return particle;
-    },
-    
-    addInitializer: function (initializer) {
-        this._initializers.push(initializer);
-    },
-    
-    addAction: function (action) {
-        this._actions.push(action);
-    },
-
-    removeInitializer: function (initializer) {
-		var index = this._initializers.indexOf(initializer);
-		if (index > -1) {
-			this._initializers.splice( index, 1 );
-		}
-    },
-
-    removeAction: function (action) {
-		var index = this._actions.indexOf(action);
-		if (index > -1) {
-			this._actions.splice( index, 1 );
-		}
-		//console.log('removeAction', index, this._actions);
-    },
-    
-    addCallback: function(name, callback) {
-        this.callbacks[name] = callback;
-    },
-    
-    dispatchEvent: function(name, args) {
-        var callback = this.callbacks[name];
-        if (callback) {
-            callback(args);
-        }
-    
-    }
-    
-
-};
-
-
-/*
- * Constant Names for
- * Events called by emitter.dispatchEvent()
- * 
- */
-SPARKS.EVENT_PARTICLE_CREATED = "created"
-SPARKS.EVENT_PARTICLE_UPDATED = "updated"
-SPARKS.EVENT_PARTICLE_DEAD = "dead";
-SPARKS.EVENT_LOOP_UPDATED = "loopUpdated";
-
-
-
-/*
- * Steady Counter attempts to produces a particle rate steadily
- *
- */
-
-// Number of particles per seconds
-SPARKS.SteadyCounter = function(rate) {
-    this.rate = rate;
-    
-	// we use a shortfall counter to make up for slow emitters 
-	this.leftover = 0;
-	
-};
-
-SPARKS.SteadyCounter.prototype.updateEmitter = function(emitter, time) {
-
-	var targetRelease = time * this.rate + this.leftover;
-	var actualRelease = Math.floor(targetRelease);
-	
-	this.leftover = targetRelease - actualRelease;
-	
-	return actualRelease;
-};
-
-
-/*
- * Shot Counter produces specified particles 
- * on a single impluse or burst
- */
-
-SPARKS.ShotCounter = function(particles) {
-	this.particles = particles;
-	this.used = false;
-};
-
-SPARKS.ShotCounter.prototype.updateEmitter = function(emitter, time) {
-
-	if (this.used) {
-		return 0;
-	} else {
-		this.used = true;
-	}
-	
-	return this.particles;
-};
-
-
-/********************************
-* Particle Class
-*
-*   Represents a single particle
-*********************************/
-SPARKS.Particle = function() {
-
-    /**
-     * The lifetime of the particle, in seconds.
-     */
-    this.lifetime = 0;
-    
-    /**
-     * The age of the particle, in seconds.
-     */
-    this.age = 0;
-    
-    /**
-     * The energy of the particle.
-     */
-    this.energy = 1;
-    
-    /**
-     * Whether the particle is dead and should be removed from the stage.
-     */
-    this.isDead = false;
-    
-    this.target = null; // tag
-    
-    /**
-     * For 3D
-     */
-     
-     this.position = SPARKS.VectorPool.get().set(0,0,0); //new THREE.Vector3( 0, 0, 0 );
-     this.velocity = SPARKS.VectorPool.get().set(0,0,0); //new THREE.Vector3( 0, 0, 0 );
-	this._oldvelocity = SPARKS.VectorPool.get().set(0,0,0);
-     // rotation vec3
-     // angVelocity vec3
-     // faceAxis vec3
-    
-};
-
-
-/********************************
-* Action Classes
-*
-*   An abstract class which have
-*   update function
-*********************************/
-SPARKS.Action = function() {
-    this._priority = 0;
-};
-
-
-SPARKS.Age = function(easing) {
-    this._easing = (easing == null) ? TWEEN.Easing.Linear.EaseNone : easing;
-};
-
-SPARKS.Age.prototype.update = function (emitter, particle, time) {
-    particle.age += time;
-    if( particle.age >= particle.lifetime )
-    {
-        particle.energy = 0;
-        particle.isDead = true;
-    }
-    else
-    {
-        var t = this._easing(particle.age / particle.lifetime);
-        particle.energy = -1 * t + 1;
-    }
-};
-
-/*
-// Mark particle as dead when particle's < 0
-
-SPARKS.Death = function(easing) {
-    this._easing = (easing == null) ? TWEEN.Linear.EaseNone : easing;
-};
-
-SPARKS.Death.prototype.update = function (emitter, particle, time) {
-    if (particle.life <= 0) {
-        particle.isDead = true;
-    }
-};
-*/
-			
-
-SPARKS.Move = function() {
-    
-};
-
-SPARKS.Move.prototype.update = function(emitter, particle, time) {
-    // attempt verlet velocity updating.
-    var p = particle.position;
-	var v = particle.velocity;
-    var old = particle._oldvelocity;
-	
-	if (this._velocityVerlet) {	
-		p.x += (v.x + old.x) * 0.5 * time;
-		p.y += (v.y + old.y) * 0.5 * time;
-		p.z += (v.z + old.z) * 0.5 * time;
-	} else {
-		p.x += v.x * time;
-		p.y += v.y * time;
-		p.z += v.z * time;
-	}
-
-    //  OldVel = Vel;
-    // Vel = Vel + Accel * dt;
-    // Pos = Pos + (vel + Vel + Accel * dt) * 0.5 * dt;
-	
-
-
-};
-
-/* Marks particles found in specified zone dead */
-SPARKS.DeathZone = function(zone) {
-    this.zone = zone;
-};
-
-SPARKS.DeathZone.prototype.update = function(emitter, particle, time) {
-    
-    if (this.zone.contains(particle.position)) {
-		particle.isDead = true;
-	}
-
-};
-
-/*
- * SPARKS.ActionZone applies an action when particle is found in zone
- */
-SPARKS.ActionZone = function(action, zone) {
-	this.action = action;
-    this.zone = zone;
-};
-
-SPARKS.ActionZone.prototype.update = function(emitter, particle, time) {
-
-    if (this.zone.contains(particle.position)) {
-		this.action.update( emitter, particle, time );
-	}
-
-};
-
-/*
- * Accelerate action affects velocity in specified 3d direction 
- */
-SPARKS.Accelerate = function(x,y,z) {
-	
-	if (x instanceof THREE.Vector3) {
-		this.acceleration = x;
-		return;
-	}
-
-    this.acceleration = new THREE.Vector3(x,y,z);
-    
-};
-
-SPARKS.Accelerate.prototype.update = function(emitter, particle, time) {
-    var acc = this.acceleration;
-    
-    var v = particle.velocity;
-    
-	particle._oldvelocity.set(v.x, v.y, v.z);
-	
-    v.x += acc.x * time;
-    v.y += acc.y * time;
-    v.z += acc.z * time; 
-
-};
-
-/*
- * Accelerate Factor accelerate based on a factor of particle's velocity.
- */
-SPARKS.AccelerateFactor = function(factor) {
-    this.factor = factor;
-};
-
-SPARKS.AccelerateFactor.prototype.update = function(emitter, particle, time) {
-    var factor = this.factor;
-    
-    var v = particle.velocity;
-	var len = v.length();
-	var adjFactor;
-    if (len>0) {
-
-		adjFactor = factor * time / len;
-		adjFactor += 1;
-		
-		v.multiplyScalar(adjFactor);
-		// v.x *= adjFactor;
-		// 	    v.y *= adjFactor;
-		// 	    v.z *= adjFactor; 
-	}
-
-};
-
-/*
-AccelerateNormal
- * AccelerateVelocity affects velocity based on its velocity direction
- */
-SPARKS.AccelerateVelocity = function(factor) {
-
-	this.factor = factor;
-
-};
-
-SPARKS.AccelerateVelocity.prototype.update = function(emitter, particle, time) {
-    var factor = this.factor;
-
-    var v = particle.velocity;
-
-
-    v.z += - v.x * factor;
-    v.y += v.z * factor;
-    v.x +=  v.y * factor;
-
-};
-
-
-/* Set the max ammount of x,y,z drift movements in a second */
-SPARKS.RandomDrift = function(x,y,z) {
-	if (x instanceof THREE.Vector3) {
-		this.drift = x;
-		return;
-	}
-
-    this.drift = new THREE.Vector3(x,y,z);
-}
-
-
-SPARKS.RandomDrift.prototype.update = function(emitter, particle, time) {
-    var drift = this.drift;
-    
-    var v = particle.velocity;
-    
-    v.x += ( Math.random() - 0.5 ) * drift.x * time;
-    v.y += ( Math.random() - 0.5 ) * drift.y * time;
-    v.z += ( Math.random() - 0.5 ) * drift.z * time;
-
-};
-
-/********************************
-* Zone Classes
-*
-*   An abstract classes which have
-*   getLocation() function
-*********************************/
-SPARKS.Zone = function() {
-};
-
-// TODO, contains() for Zone
-
-SPARKS.PointZone = function(pos) {
-    this.pos = pos;
-};
-
-SPARKS.PointZone.prototype.getLocation = function() {
-    return this.pos;
-};
-
-SPARKS.PointZone = function(pos) {
-    this.pos = pos;
-};
-
-SPARKS.PointZone.prototype.getLocation = function() {
-    return this.pos;
-};
-
-SPARKS.LineZone = function(start, end) {
-    this.start = start;
-	this.end = end;
-	this._length = end.clone().subSelf( start );
-};
-
-SPARKS.LineZone.prototype.getLocation = function() {
-    var len = this._length.clone();
-
-	len.multiplyScalar( Math.random() );
-	return len.addSelf( this.start );
-	
-};
-
-// Basically a RectangleZone
-SPARKS.ParallelogramZone = function(corner, side1, side2) {
-    this.corner = corner;
-	this.side1 = side1;
-	this.side2 = side2;
-};
-
-SPARKS.ParallelogramZone.prototype.getLocation = function() {
-    
-	var d1 = this.side1.clone().multiplyScalar( Math.random() );
-	var d2 = this.side2.clone().multiplyScalar( Math.random() );
-	d1.addSelf(d2);
-	return d1.addSelf( this.corner );
-	
-};
-
-SPARKS.CubeZone = function(position, x, y, z) {
-    this.position = position;
-	this.x = x;
-	this.y = y;
-	this.z = z;
-};
-
-SPARKS.CubeZone.prototype.getLocation = function() {
-    //TODO use pool?
-
-	var location = this.position.clone();
-	location.x += Math.random() * this.x;
-	location.y += Math.random() * this.y;
-	location.z += Math.random() * this.z;
-	
-	return location;
-	
-};
-
-
-SPARKS.CubeZone.prototype.contains = function(position) {
-
-	var startX = this.position.x;
-	var startY = this.position.y;
-	var startZ = this.position.z;
-	var x = this.x; // width
-	var y = this.y; // depth
-	var z = this.z; // height
-	
-	if (x<0) {
-		startX += x;
-		x = Math.abs(x);
-	}
-	
-	if (y<0) {
-		startY += y;
-		y = Math.abs(y);
-	}
-	
-	if (z<0) {
-		startZ += z;
-		z = Math.abs(z);
-	}
-	
-	var diffX = position.x - startX;
-	var diffY = position.y - startY;
-	var diffZ = position.z - startZ;
-	
-	if ( (diffX > 0) && (diffX < x) && 
-			(diffY > 0) && (diffY < y) && 
-			(diffZ > 0) && (diffZ < z) ) {
-		return true;
-	}
-	
-	return false;
-	
-};
-
-
-
-/**
- * The constructor creates a DiscZone 3D zone.
- * 
- * @param centre The point at the center of the disc.
- * @param normal A vector normal to the disc.
- * @param outerRadius The outer radius of the disc.
- * @param innerRadius The inner radius of the disc. This defines the hole 
- * in the center of the disc. If set to zero, there is no hole. 
- */
-
-/*
-// BUGGY!!
-SPARKS.DiscZone = function(center, radiusNormal, outerRadius, innerRadius) {
-    this.center = center;
-	this.radiusNormal = radiusNormal;
-	this.outerRadius = (outerRadius==undefined) ? 0 : outerRadius;
-	this.innerRadius = (innerRadius==undefined) ? 0 : innerRadius;
-	
-};
-
-SPARKS.DiscZone.prototype.getLocation = function() {
-    var rand = Math.random();
-	var _innerRadius = this.innerRadius;
-	var _outerRadius = this.outerRadius;
-	var center = this.center;
-	var _normal = this.radiusNormal;
-	
-	_distToOrigin = _normal.dot( center );
-	
-	var radius = _innerRadius + (1 - rand * rand ) * ( _outerRadius - _innerRadius );
-	var angle = Math.random() * SPARKS.Utils.TWOPI;
-	
-	var _distToOrigin = _normal.dot( center );
-	var axes = SPARKS.Utils.getPerpendiculars( _normal.clone() );
-	var _planeAxis1 = axes[0];
-	var _planeAxis2 = axes[1];
-	
-	var p = _planeAxis1.clone();
-	p.multiplyScalar( radius * Math.cos( angle ) );
-	var p2 = _planeAxis2.clone();
-	p2.multiplyScalar( radius * Math.sin( angle ) );
-	p.addSelf( p2 );
-	return _center.add( p );
-	
-};
-*/
-
-SPARKS.SphereCapZone = function(x, y, z, minr, maxr, angle) {
-    this.x = x;
-    this.y = y;
-    this.z = z;
-    this.minr = minr;
-    this.maxr = maxr;
-    this.angle = angle;
-};
-
-SPARKS.SphereCapZone.prototype.getLocation = function() {
-    var theta = Math.PI *2  * SPARKS.Utils.random();
-    var r = SPARKS.Utils.random();
-    
-    //new THREE.Vector3
-    var v =  SPARKS.VectorPool.get().set(r * Math.cos(theta), -1 / Math.tan(this.angle * SPARKS.Utils.DEGREE_TO_RADIAN), r * Math.sin(theta));
-    
-    //v.length = StardustMath.interpolate(0, _minRadius, 1, _maxRadius, Math.random());
-            
-    var i = this.minr - ((this.minr-this.maxr) *  Math.random() );
-    v.multiplyScalar(i);
-
-	v.__markedForReleased = true;
-    
-    return v;
-};
-
-
-/********************************
-* Initializer Classes
-*
-*   Classes which initializes
-*   particles. Implements initialize( emitter:Emitter, particle:Particle )
-*********************************/
-
-// Specifies random life between max and min
-SPARKS.Lifetime = function(min, max) {
-    this._min = min;
-    
-    this._max = max ? max : min;
-    
-};
-
-SPARKS.Lifetime.prototype.initialize = function( emitter/*Emitter*/, particle/*Particle*/ ) {
-    particle.lifetime = this._min + SPARKS.Utils.random() * ( this._max - this._min );
-};
-
-
-SPARKS.Position = function(zone) {
-    this.zone = zone;
-};
-
-SPARKS.Position.prototype.initialize = function( emitter/*Emitter*/, particle/*Particle*/ ) {
-    var pos = this.zone.getLocation();
-    particle.position.set(pos.x, pos.y, pos.z);
-};
-
-SPARKS.Velocity = function(zone) {
-    this.zone = zone;
-};
-
-SPARKS.Velocity.prototype.initialize = function( emitter/*Emitter*/, particle/*Particle*/ ) {
-    var pos = this.zone.getLocation();
-    particle.velocity.set(pos.x, pos.y, pos.z);
-	if (pos.__markedForReleased) {
-		//console.log("release");
-		SPARKS.VectorPool.release(pos);
-		pos.__markedForReleased = false;
-	}
-};
-
-SPARKS.Target = function(target, callback) {
-    this.target = target;
-    this.callback = callback;
-};
-
-SPARKS.Target.prototype.initialize = function( emitter, particle ) {
-
-    if (this.callback) {
-        particle.target = this.callback();
-    } else {
-        particle.target = this.target;
-    }
-
-};
-
-/********************************
-* VectorPool 
-*
-*  Reuse much of Vectors if possible
-*********************************/
-
-SPARKS.VectorPool = {
-	__pools: [],
-
-	// Get a new Vector
-	get: function() {
-		if (this.__pools.length>0) {
-			return this.__pools.pop();
-		}
-		
-		return this._addToPool();
-		
-	},
-	
-	// Release a vector back into the pool
-	release: function(v) {
-		this.__pools.push(v);
-	},
-	
-	// Create a bunch of vectors and add to the pool
-	_addToPool: function() {
-		//console.log("creating some pools");
-		
-		for (var i=0, size = 100; i < size; i++) {
-			this.__pools.push(new THREE.Vector3());
-		}
-		
-		return new THREE.Vector3();
-		
-	}
-	
-	
-	
-};
-
-
-/********************************
-* Util Classes
-*
-*   Classes which initializes
-*   particles. Implements initialize( emitter:Emitter, particle:Particle )
-*********************************/
-SPARKS.Utils = {
-    random: function() {
-        return Math.random();
-    },
-    DEGREE_TO_RADIAN: Math.PI / 180,
-	TWOPI: Math.PI * 2,
-
-	getPerpendiculars: function(normal) {
-		var p1 = this.getPerpendicular( normal );
-		var p2 = normal.cross( p1 );
-		p2.normalize();
-		return [ p1, p2 ];
-	},
-	
-	getPerpendicular: function( v )
-	{
-		if( v.x == 0 )
-		{
-			return new THREE.Vector3D( 1, 0, 0 );
-		}
-		else
-		{
-			var temp = new THREE.Vector3( v.y, -v.x, 0 );
-			return temp.normalize();
-		}
-	}
-
-};
\ No newline at end of file
diff --git a/emperor/support_files/js/js/Stats.js b/emperor/support_files/js/js/Stats.js
deleted file mode 100644
index 6cdeeb3..0000000
--- a/emperor/support_files/js/js/Stats.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// stats.js r8 - http://github.com/mrdoob/stats.js
-var Stats=function(){var h,a,n=0,o=0,i=Date.now(),u=i,p=i,l=0,q=1E3,r=0,e,j,f,b=[[16,16,48],[0,255,255]],m=0,s=1E3,t=0,d,k,g,c=[[16,48,16],[0,255,0]];h=document.createElement("div");h.style.cursor="pointer";h.style.width="80px";h.style.opacity="0.9";h.style.zIndex="10001";h.addEventListener("mousedown",function(a){a.preventDefault();n=(n+1)%2;n==0?(e.style.display="block",d.style.display="none"):(e.style.display="none",d.style.display="block")},!1);e=document.createElement("div");e.style [...]
-"left";e.style.lineHeight="1.2em";e.style.backgroundColor="rgb("+Math.floor(b[0][0]/2)+","+Math.floor(b[0][1]/2)+","+Math.floor(b[0][2]/2)+")";e.style.padding="0 0 3px 3px";h.appendChild(e);j=document.createElement("div");j.style.fontFamily="Helvetica, Arial, sans-serif";j.style.fontSize="9px";j.style.color="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";j.style.fontWeight="bold";j.innerHTML="FPS";e.appendChild(j);f=document.createElement("div");f.style.position="relative";f.style.width="74px [...]
-"30px";f.style.backgroundColor="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";for(e.appendChild(f);f.children.length<74;)a=document.createElement("span"),a.style.width="1px",a.style.height="30px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+b[0][0]+","+b[0][1]+","+b[0][2]+")",f.appendChild(a);d=document.createElement("div");d.style.textAlign="left";d.style.lineHeight="1.2em";d.style.backgroundColor="rgb("+Math.floor(c[0][0]/2)+","+Math.floor(c[0][1]/2)+","+Math.floor(c[0][2]/2)+")" [...]
-"0 0 3px 3px";d.style.display="none";h.appendChild(d);k=document.createElement("div");k.style.fontFamily="Helvetica, Arial, sans-serif";k.style.fontSize="9px";k.style.color="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";k.style.fontWeight="bold";k.innerHTML="MS";d.appendChild(k);g=document.createElement("div");g.style.position="relative";g.style.width="74px";g.style.height="30px";g.style.backgroundColor="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";for(d.appendChild(g);g.children.length<74;)a=d [...]
-a.style.width="1px",a.style.height=Math.random()*30+"px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+c[0][0]+","+c[0][1]+","+c[0][2]+")",g.appendChild(a);return{domElement:h,update:function(){i=Date.now();m=i-u;s=Math.min(s,m);t=Math.max(t,m);k.textContent=m+" MS ("+s+"-"+t+")";var a=Math.min(30,30-m/200*30);g.appendChild(g.firstChild).style.height=a+"px";u=i;o++;if(i>p+1E3)l=Math.round(o*1E3/(i-p)),q=Math.min(q,l),r=Math.max(r,l),j.textContent=l+" FPS ("+q+"-"+r+")",a=Math.mi [...]
-100*30),f.appendChild(f.firstChild).style.height=a+"px",p=i,o=0}}};
-
diff --git a/emperor/support_files/js/js/Tween.js b/emperor/support_files/js/js/Tween.js
deleted file mode 100644
index 67824ab..0000000
--- a/emperor/support_files/js/js/Tween.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// tween.js r5 - http://github.com/sole/tween.js
-var TWEEN=TWEEN||function(){var a,e,c=60,b=false,h=[];return{setFPS:function(f){c=f||60},start:function(f){arguments.length!=0&&this.setFPS(f);e=setInterval(this.update,1E3/c)},stop:function(){clearInterval(e)},setAutostart:function(f){(b=f)&&!e&&this.start()},add:function(f){h.push(f);b&&!e&&this.start()},getAll:function(){return h},removeAll:function(){h=[]},remove:function(f){a=h.indexOf(f);a!==-1&&h.splice(a,1)},update:function(f){a=0;num_tweens=h.length;for(f=f||Date.now();a<num_twe [...]
-else{h.splice(a,1);num_tweens--}num_tweens==0&&b==true&&this.stop()}}}();
-TWEEN.Tween=function(a){var e={},c={},b={},h=1E3,f=0,j=null,n=TWEEN.Easing.Linear.EaseNone,k=null,l=null,m=null;this.to=function(d,g){if(g!==null)h=g;for(var i in d)if(a[i]!==null)b[i]=d[i];return this};this.start=function(d){TWEEN.add(this);j=d?d+f:Date.now()+f;for(var g in b)if(a[g]!==null){e[g]=a[g];c[g]=b[g]-a[g]}return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(d){f=d;return this};this.easing=function(d){n=d;return this};this.chain=function(d){k=d [...]
-function(d){l=d;return this};this.onComplete=function(d){m=d;return this};this.update=function(d){var g,i;if(d<j)return true;d=(d-j)/h;d=d>1?1:d;i=n(d);for(g in c)a[g]=e[g]+c[g]*i;l!==null&&l.call(a,i);if(d==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a};
-TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a};
-TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1};
-TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)};
-TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b))};
-TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/b)+1};
-TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/b)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1};
-TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375};
-TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5};
\ No newline at end of file
diff --git a/emperor/support_files/js/js/ctm/CTMLoader.js b/emperor/support_files/js/js/ctm/CTMLoader.js
deleted file mode 100644
index b045648..0000000
--- a/emperor/support_files/js/js/ctm/CTMLoader.js
+++ /dev/null
@@ -1,821 +0,0 @@
-/**
- * Loader for CTM encoded models generated by OpenCTM tools:
- *	http://openctm.sourceforge.net/
- *
- * Uses js-openctm library by Juan Mellado
- *	http://code.google.com/p/js-openctm/
- *
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.CTMLoader = function ( context, showStatus ) {
-
-	this.context = context;
-
-	THREE.Loader.call( this, showStatus );
-
-};
-
-THREE.CTMLoader.prototype = new THREE.Loader();
-THREE.CTMLoader.prototype.constructor = THREE.CTMLoader;
-
-
-// Load multiple CTM parts defined in JSON
-
-THREE.CTMLoader.prototype.loadParts = function( url, callback, useWorker, useBuffers, basePath ) {
-
-	var scope = this;
-
-	var xhr = new XMLHttpRequest();
-
-	basePath = basePath ? basePath : this.extractUrlbase( url );
-
-	xhr.onreadystatechange = function() {
-
-		if ( xhr.readyState == 4 ) {
-
-			if ( xhr.status == 200 || xhr.status == 0 ) {
-
-				var jsonObject = JSON.parse( xhr.responseText );
-
-				var materials = [], geometries = [], counter = 0;
-
-				function callbackFinal( geometry ) {
-
-					counter += 1;
-
-					geometries.push( geometry );
-
-					if ( counter === jsonObject.offsets.length ) {
-
-						callback( geometries, materials );
-
-					}
-
-				}
-
-
-				// init materials
-
-				for ( var i = 0; i < jsonObject.materials.length; i ++ ) {
-
-					materials[ i ] = THREE.Loader.prototype.createMaterial( jsonObject.materials[ i ], basePath );
-
-				}
-
-				// load joined CTM file
-
-				var partUrl = basePath + jsonObject.data;
-				scope.load( partUrl, callbackFinal, useWorker, useBuffers, jsonObject.offsets );
-
-			}
-
-		}
-
-	}
-
-	xhr.open( "GET", url, true );
-	if ( xhr.overrideMimeType ) xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
-	xhr.setRequestHeader( "Content-Type", "text/plain" );
-	xhr.send( null );
-
-};
-
-// Load CTMLoader compressed models
-//  - parameters
-//		- url (required)
-//		- callback (required)
-
-THREE.CTMLoader.prototype.load = function( url, callback, useWorker, useBuffers, offsets ) {
-
-	var scope = this;
-
-	offsets = offsets !== undefined ? offsets : [ 0 ];
-
-	var xhr = new XMLHttpRequest(),
-		callbackProgress = null;
-
-	var length = 0;
-
-	xhr.onreadystatechange = function() {
-
-		if ( xhr.readyState == 4 ) {
-
-			if ( xhr.status == 200 || xhr.status == 0 ) {
-
-				var binaryData = xhr.responseText;
-
-				//var s = Date.now();
-
-				if ( useWorker ) {
-
-					var worker = new Worker( "js/ctm/CTMWorker.js" );
-
-					worker.onmessage = function( event ) {
-
-						var files = event.data;
-
-						for ( var i = 0; i < files.length; i ++ ) {
-
-							var ctmFile = files[ i ];
-
-							if ( useBuffers ) {
-
-								scope.createModelBuffers( ctmFile, callback );
-
-							} else {
-
-								scope.createModelClassic( ctmFile, callback );
-
-							}
-
-						}
-
-						//var e = Date.now();
-						//console.log( "CTM data parse time [worker]: " + (e-s) + " ms" );
-
-					};
-
-					worker.postMessage( { "data": binaryData, "offsets": offsets } );
-
-				} else {
-
-
-					for ( var i = 0; i < offsets.length; i ++ ) {
-
-						var stream = new CTM.Stream( binaryData );
-						stream.offset = offsets[ i ];
-
-						var ctmFile = new CTM.File( stream );
-
-						if ( useBuffers ) {
-
-							scope.createModelBuffers( ctmFile, callback );
-
-						} else {
-
-							scope.createModelClassic( ctmFile, callback );
-
-						}
-
-					}
-
-					//var e = Date.now();
-					//console.log( "CTM data parse time [inline]: " + (e-s) + " ms" );
-
-				}
-
-			} else {
-
-				console.error( "Couldn't load [" + url + "] [" + xhr.status + "]" );
-
-			}
-
-		} else if ( xhr.readyState == 3 ) {
-
-			if ( callbackProgress ) {
-
-				if ( length == 0 ) {
-
-					length = xhr.getResponseHeader( "Content-Length" );
-
-				}
-
-				callbackProgress( { total: length, loaded: xhr.responseText.length } );
-
-			}
-
-		} else if ( xhr.readyState == 2 ) {
-
-			length = xhr.getResponseHeader( "Content-Length" );
-
-		}
-
-	}
-
-	xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
-	xhr.open( "GET", url, true );
-	xhr.send( null );
-
-};
-
-
-THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
-
-	var gl = this.context;
-
-	var Model = function ( ) {
-
-		var scope = this;
-
-		var dynamic = false,
-		computeNormals = true,
-		normalizeNormals = true,
-		reorderVertices = true;
-
-		scope.materials = [];
-
-		THREE.BufferGeometry.call( this );
-
-		// init GL buffers
-
-		var vertexIndexArray = file.body.indices,
-		vertexPositionArray = file.body.vertices,
-		vertexNormalArray = file.body.normals;
-
-		var vertexUvArray, vertexColorArray;
-
-		if ( file.body.uvMaps !== undefined && file.body.uvMaps.length > 0 ) {
-
-			vertexUvArray = file.body.uvMaps[ 0 ].uv;
-
-		}
-
-		if ( file.body.attrMaps !== undefined && file.body.attrMaps.length > 0 && file.body.attrMaps[ 0 ].name === "Color" ) {
-
-			vertexColorArray = file.body.attrMaps[ 0 ].attr;
-
-		}
-
-		//console.log( "vertices", vertexPositionArray.length/3 );
-		//console.log( "triangles", vertexIndexArray.length/3 );
-
-		// compute face normals from scratch
-		// (must be done before computing offsets)
-
-		if ( vertexNormalArray === undefined && computeNormals ) {
-
-			var nElements = vertexPositionArray.length;
-
-			vertexNormalArray = new Float32Array( nElements );
-
-			var vA, vB, vC, x, y, z,
-
-			pA = new THREE.Vector3(),
-			pB = new THREE.Vector3(),
-			pC = new THREE.Vector3(),
-
-			cb = new THREE.Vector3(),
-			ab = new THREE.Vector3();
-
-			for ( var i = 0; i < vertexIndexArray.length; i += 3 ) {
-
-				vA = vertexIndexArray[ i ];
-				vB = vertexIndexArray[ i + 1 ];
-				vC = vertexIndexArray[ i + 2 ];
-
-				x = vertexPositionArray[ vA * 3 ];
-				y = vertexPositionArray[ vA * 3 + 1 ];
-				z = vertexPositionArray[ vA * 3 + 2 ];
-				pA.set( x, y, z );
-
-				x = vertexPositionArray[ vB * 3 ];
-				y = vertexPositionArray[ vB * 3 + 1 ];
-				z = vertexPositionArray[ vB * 3 + 2 ];
-				pB.set( x, y, z );
-
-				x = vertexPositionArray[ vC * 3 ];
-				y = vertexPositionArray[ vC * 3 + 1 ];
-				z = vertexPositionArray[ vC * 3 + 2 ];
-				pC.set( x, y, z );
-
-				cb.sub( pC, pB );
-				ab.sub( pA, pB );
-				cb.crossSelf( ab );
-
-				vertexNormalArray[ vA * 3 ] 	+= cb.x;
-				vertexNormalArray[ vA * 3 + 1 ] += cb.y;
-				vertexNormalArray[ vA * 3 + 2 ] += cb.z;
-
-				vertexNormalArray[ vB * 3 ] 	+= cb.x;
-				vertexNormalArray[ vB * 3 + 1 ] += cb.y;
-				vertexNormalArray[ vB * 3 + 2 ] += cb.z;
-
-				vertexNormalArray[ vC * 3 ] 	+= cb.x;
-				vertexNormalArray[ vC * 3 + 1 ] += cb.y;
-				vertexNormalArray[ vC * 3 + 2 ] += cb.z;
-
-			}
-
-			if ( normalizeNormals ) {
-
-				for ( var i = 0; i < nElements; i += 3 ) {
-
-					x = vertexNormalArray[ i ];
-					y = vertexNormalArray[ i + 1 ];
-					z = vertexNormalArray[ i + 2 ];
-
-					var n = 1.0 / Math.sqrt( x * x + y * y + z * z );
-
-					vertexNormalArray[ i ] 	   *= n;
-					vertexNormalArray[ i + 1 ] *= n;
-					vertexNormalArray[ i + 2 ] *= n;
-
-				}
-
-			}
-
-		}
-
-		// reorder vertices
-		// (needed for buffer splitting, to keep together face vertices)
-
-		if ( reorderVertices ) {
-
-			var newFaces = new Uint32Array( vertexIndexArray.length ),
-				newVertices = new Float32Array( vertexPositionArray.length );
-
-			var newNormals, newUvs, newColors;
-
-			if ( vertexNormalArray ) newNormals = new Float32Array( vertexNormalArray.length );
-			if ( vertexUvArray ) newUvs = new Float32Array( vertexUvArray.length );
-			if ( vertexColorArray ) newColors = new Float32Array( vertexColorArray.length );
-
-			var indexMap = {}, vertexCounter = 0;
-
-			function handleVertex( v ) {
-
-				if ( indexMap[ v ] === undefined ) {
-
-					indexMap[ v ] = vertexCounter;
-
-					var sx = v * 3,
-						sy = v * 3 + 1,
-						sz = v * 3 + 2,
-
-						dx = vertexCounter * 3,
-						dy = vertexCounter * 3 + 1,
-						dz = vertexCounter * 3 + 2;
-
-					newVertices[ dx ] = vertexPositionArray[ sx ];
-					newVertices[ dy ] = vertexPositionArray[ sy ];
-					newVertices[ dz ] = vertexPositionArray[ sz ];
-
-					if ( vertexNormalArray ) {
-
-						newNormals[ dx ] = vertexNormalArray[ sx ];
-						newNormals[ dy ] = vertexNormalArray[ sy ];
-						newNormals[ dz ] = vertexNormalArray[ sz ];
-
-					}
-
-					if ( vertexUvArray ) {
-
-						newUvs[ vertexCounter * 2 ] 	= vertexUvArray[ v * 2 ];
-						newUvs[ vertexCounter * 2 + 1 ] = vertexUvArray[ v * 2 + 1 ];
-
-					}
-
-					if ( vertexColorArray ) {
-
-						newColors[ vertexCounter * 4 ] 	   = vertexNormalArray[ v * 4 ];
-						newColors[ vertexCounter * 4 + 1 ] = vertexNormalArray[ v * 4 + 1 ];
-						newColors[ vertexCounter * 4 + 2 ] = vertexNormalArray[ v * 4 + 2 ];
-						newColors[ vertexCounter * 4 + 3 ] = vertexNormalArray[ v * 4 + 3 ];
-
-					}
-
-					vertexCounter += 1;
-
-				}
-
-			}
-
-			var a, b, c;
-
-			for ( var i = 0; i < vertexIndexArray.length; i += 3 ) {
-
-				a = vertexIndexArray[ i ];
-				b = vertexIndexArray[ i + 1 ];
-				c = vertexIndexArray[ i + 2 ];
-
-				handleVertex( a );
-				handleVertex( b );
-				handleVertex( c );
-
-				newFaces[ i ] 	  = indexMap[ a ];
-				newFaces[ i + 1 ] = indexMap[ b ];
-				newFaces[ i + 2 ] = indexMap[ c ];
-
-			}
-
-			vertexIndexArray = newFaces;
-			vertexPositionArray = newVertices;
-
-			if ( vertexNormalArray ) vertexNormalArray = newNormals;
-			if ( vertexUvArray ) vertexUvArray = newUvs;
-			if ( vertexColorArray ) vertexColorArray = newColors;
-
-		}
-
-		// compute offsets
-
-		scope.offsets = [];
-
-		var indices = vertexIndexArray;
-
-		var start = 0,
-			min = vertexPositionArray.length,
-			max = 0,
-			minPrev = min;
-
-		for ( var i = 0; i < indices.length; ) {
-
-			for ( var j = 0; j < 3; ++ j ) {
-
-				var idx = indices[ i ++ ];
-
-				if ( idx < min ) min = idx;
-				if ( idx > max ) max = idx;
-
-			}
-
-			if ( max - min > 65535 ) {
-
-				i -= 3;
-
-				for ( var k = start; k < i; ++ k ) {
-
-					indices[ k ] -= minPrev;
-
-				}
-
-				scope.offsets.push( { start: start, count: i - start, index: minPrev } );
-
-				start = i;
-				min = vertexPositionArray.length;
-				max = 0;
-
-			}
-
-			minPrev = min;
-
-		}
-
-		for ( var k = start; k < i; ++ k ) {
-
-			indices[ k ] -= minPrev;
-
-		}
-
-		scope.offsets.push( { start: start, count: i - start, index: minPrev } );
-
-
-		// indices
-
-		scope.vertexIndexBuffer = gl.createBuffer();
-		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, scope.vertexIndexBuffer );
-		gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( vertexIndexArray ), gl.STATIC_DRAW );
-
-		scope.vertexIndexBuffer.itemSize = 1;
-		scope.vertexIndexBuffer.numItems = vertexIndexArray.length;
-
-		// vertices
-
-		scope.vertexPositionBuffer = gl.createBuffer();
-		gl.bindBuffer( gl.ARRAY_BUFFER, scope.vertexPositionBuffer );
-		gl.bufferData( gl.ARRAY_BUFFER, vertexPositionArray, gl.STATIC_DRAW );
-
-		scope.vertexPositionBuffer.itemSize = 3;
-		scope.vertexPositionBuffer.numItems = vertexPositionArray.length;
-
-		// normals
-
-		if ( vertexNormalArray !== undefined ) {
-
-			scope.vertexNormalBuffer = gl.createBuffer();
-			gl.bindBuffer( gl.ARRAY_BUFFER, scope.vertexNormalBuffer );
-			gl.bufferData( gl.ARRAY_BUFFER, vertexNormalArray, gl.STATIC_DRAW );
-
-			scope.vertexNormalBuffer.itemSize = 3;
-			scope.vertexNormalBuffer.numItems = vertexNormalArray.length;
-
-		}
-
-		// uvs
-
-		if ( vertexUvArray !== undefined ) {
-
-			// "fix" flipping
-
-			for ( var i = 0; i < vertexUvArray.length; i += 2 ) {
-
-				vertexUvArray[ i + 1 ] = 1 - vertexUvArray[ i + 1 ];
-
-			}
-
-			scope.vertexUvBuffer = gl.createBuffer();
-			gl.bindBuffer( gl.ARRAY_BUFFER, scope.vertexUvBuffer );
-			gl.bufferData( gl.ARRAY_BUFFER, vertexUvArray, gl.STATIC_DRAW );
-
-			scope.vertexUvBuffer.itemSize = 2;
-			scope.vertexUvBuffer.numItems = vertexUvArray.length;
-
-		}
-
-		// colors
-
-		if ( vertexColorArray !== undefined ) {
-
-			scope.vertexColorBuffer = gl.createBuffer();
-			gl.bindBuffer( gl.ARRAY_BUFFER, scope.vertexColorBuffer );
-			gl.bufferData( gl.ARRAY_BUFFER, vertexColorArray, gl.STATIC_DRAW );
-
-			scope.vertexColorBuffer.itemSize = 4;
-			scope.vertexColorBuffer.numItems = vertexColorArray.length;
-
-		}
-
-		// compute bounding sphere and bounding box
-		// (must do it now as we don't keep typed arrays after setting GL buffers)
-
-		scope.boundingBox = { min: new THREE.Vector3( Infinity, Infinity, Infinity ), max: new THREE.Vector3( -Infinity, -Infinity, -Infinity ) };
-
-		var vertices = file.body.vertices,
-			bb = scope.boundingBox,
-			radius, maxRadius = 0,
-			x, y, z;
-
-		for ( var i = 0, il = vertices.length; i < il; i += 3 ) {
-
-			x = vertices[ i ];
-			y = vertices[ i + 1 ];
-			z = vertices[ i + 2 ];
-
-			// bounding sphere
-
-			radius = Math.sqrt( x * x + y * y + z * z );
-			if ( radius > maxRadius ) maxRadius = radius;
-
-			// bounding box
-
-			if ( x < bb.min.x ) {
-
-				bb.min.x = x;
-
-			} else if ( x > bb.max.x ) {
-
-				bb.max.x = x;
-
-			}
-
-			if ( y < bb.min.y ) {
-
-				bb.min.y = y;
-
-			} else if ( y > bb.max.y ) {
-
-				bb.max.y = y;
-
-			}
-
-			if ( z < bb.min.z ) {
-
-				bb.min.z = z;
-
-			} else if ( z > bb.max.z ) {
-
-				bb.max.z = z;
-
-			}
-
-		}
-
-		scope.boundingSphere = { radius: maxRadius };
-
-		// keep references to typed arrays
-
-		if ( dynamic ) {
-
-			scope.vertexIndexArray = vertexIndexArray;
-			scope.vertexPositionArray = vertexPositionArray;
-			scope.vertexNormalArray = vertexNormalArray;
-			scope.vertexUvArray = vertexUvArray;
-			scope.vertexColorArray = vertexColorArray;
-
-		}
-
-	}
-
-	Model.prototype = new THREE.BufferGeometry();
-	Model.prototype.constructor = Model;
-
-	callback( new Model() );
-
-};
-
-THREE.CTMLoader.prototype.createModelClassic = function ( file, callback ) {
-
-	var Model = function ( ) {
-
-		var scope = this;
-
-		scope.materials = [];
-
-		THREE.Geometry.call( this );
-
-		var normals = [],
-			uvs = [],
-			colors = [];
-
-		init_vertices( file.body.vertices );
-
-		if ( file.body.normals !== undefined )
-			init_normals( file.body.normals );
-
-		if ( file.body.uvMaps !== undefined && file.body.uvMaps.length > 0 )
-			init_uvs( file.body.uvMaps[ 0 ].uv );
-
-		if ( file.body.attrMaps !== undefined && file.body.attrMaps.length > 0 && file.body.attrMaps[ 0 ].name === "Color" )
-			init_colors( file.body.attrMaps[ 0 ].attr );
-
-		var hasNormals = normals.length > 0 ? true : false,
-			hasUvs = uvs.length > 0 ? true : false,
-			hasColors = colors.length > 0 ? true : false;
-
-		init_faces( file.body.indices );
-
-		this.computeCentroids();
-		this.computeFaceNormals();
-		//this.computeTangents();
-
-		function init_vertices( buffer ) {
-
-			var x, y, z, i, il = buffer.length;
-
-			for( i = 0; i < il; i += 3 ) {
-
-				x = buffer[ i ];
-				y = buffer[ i + 1 ];
-				z = buffer[ i + 2 ];
-
-				vertex( scope, x, y, z );
-
-			}
-
-		};
-
-		function init_normals( buffer ) {
-
-			var x, y, z, i, il = buffer.length;
-
-			for( i = 0; i < il; i += 3 ) {
-
-				x = buffer[ i ];
-				y = buffer[ i + 1 ];
-				z = buffer[ i + 2 ];
-
-				normals.push( x, y, z );
-
-			}
-
-		};
-
-		function init_colors( buffer ) {
-
-			var r, g, b, a, i, il = buffer.length;
-
-			for( i = 0; i < il; i += 4 ) {
-
-				r = buffer[ i ];
-				g = buffer[ i + 1 ];
-				b = buffer[ i + 2 ];
-				a = buffer[ i + 3 ];
-
-				var color = new THREE.Color();
-				color.setRGB( r, g, b );
-
-				colors.push( color );
-
-			}
-
-		};
-
-
-		function init_uvs( buffer ) {
-
-			var u, v, i, il = buffer.length;
-
-			for( i = 0; i < il; i += 2 ) {
-
-				u = buffer[ i ];
-				v = buffer[ i + 1 ];
-
-				uvs.push( u, 1 - v );
-
-			}
-
-		};
-
-		function init_faces( buffer ) {
-
-			var a, b, c,
-				u1, v1, u2, v2, u3, v3,
-				m, face,
-				i, il = buffer.length;
-
-			m = 0; // all faces defaulting to material 0
-
-			for( i = 0; i < il; i += 3 ) {
-
-				a = buffer[ i ];
-				b = buffer[ i + 1 ];
-				c = buffer[ i + 2 ];
-
-				if ( hasNormals ){
-
-					face = f3n( scope, normals, a, b, c, m, a, b, c );
-
-				} else {
-
-					face = f3( scope, a, b, c, m );
-
-				}
-
-				if ( hasColors ) {
-
-					face.vertexColors[ 0 ] = colors[ a ];
-					face.vertexColors[ 1 ] = colors[ b ];
-					face.vertexColors[ 2 ] = colors[ c ];
-
-				}
-
-				if ( hasUvs ) {
-
-					u1 = uvs[ a * 2 ];
-					v1 = uvs[ a * 2 + 1 ];
-
-					u2 = uvs[ b * 2 ];
-					v2 = uvs[ b * 2 + 1 ];
-
-					u3 = uvs[ c * 2 ];
-					v3 = uvs[ c * 2 + 1 ];
-
-					uv3( scope.faceVertexUvs[ 0 ], u1, v1, u2, v2, u3, v3 );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	function vertex ( scope, x, y, z ) {
-
-		scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
-
-	};
-
-	function f3 ( scope, a, b, c, mi ) {
-
-		var face = new THREE.Face3( a, b, c, null, null, mi );
-
-		scope.faces.push( face );
-
-		return face;
-
-	};
-
-	function f3n ( scope, normals, a, b, c, mi, na, nb, nc ) {
-
-		var nax = normals[ na * 3     ],
-			nay = normals[ na * 3 + 1 ],
-			naz = normals[ na * 3 + 2 ],
-
-			nbx = normals[ nb * 3     ],
-			nby = normals[ nb * 3 + 1 ],
-			nbz = normals[ nb * 3 + 2 ],
-
-			ncx = normals[ nc * 3     ],
-			ncy = normals[ nc * 3 + 1 ],
-			ncz = normals[ nc * 3 + 2 ];
-
-		var na = new THREE.Vector3( nax, nay, naz ),
-			nb = new THREE.Vector3( nbx, nby, nbz ),
-			nc = new THREE.Vector3( ncx, ncy, ncz );
-
-		var face = new THREE.Face3( a, b, c, [ na, nb, nc ], null, mi );
-
-		scope.faces.push( face );
-
-		return face;
-
-	};
-
-	function uv3 ( where, u1, v1, u2, v2, u3, v3 ) {
-
-		var uv = [];
-		uv.push( new THREE.UV( u1, v1 ) );
-		uv.push( new THREE.UV( u2, v2 ) );
-		uv.push( new THREE.UV( u3, v3 ) );
-		where.push( uv );
-
-	};
-
-	Model.prototype = new THREE.Geometry();
-	Model.prototype.constructor = Model;
-
-	callback( new Model() );
-
-};
diff --git a/emperor/support_files/js/js/ctm/CTMWorker.js b/emperor/support_files/js/js/ctm/CTMWorker.js
deleted file mode 100644
index cec035f..0000000
--- a/emperor/support_files/js/js/ctm/CTMWorker.js
+++ /dev/null
@@ -1,19 +0,0 @@
-importScripts( "lzma.js", "ctm.js" );
-
-self.onmessage = function( event ) {
-
-	var files = [];
-
-	for ( var i = 0; i < event.data.offsets.length; i ++ ) {
-
-		var stream = new CTM.Stream( event.data.data );
-		stream.offset = event.data.offsets[ i ];
-
-		files[ i ] = new CTM.File( stream );
-
-	}
-
-	self.postMessage( files );
-	self.close();
-
-}
diff --git a/emperor/support_files/js/js/ctm/ctm.js b/emperor/support_files/js/js/ctm/ctm.js
deleted file mode 100644
index 4675cc1..0000000
--- a/emperor/support_files/js/js/ctm/ctm.js
+++ /dev/null
@@ -1,626 +0,0 @@
-
-var CTM = CTM || {};
-
-CTM.CompressionMethod = {
-  RAW: 0x00574152,
-  MG1: 0x0031474d,
-  MG2: 0x0032474d
-};
-
-CTM.Flags = {
-  NORMALS: 0x00000001
-};
-
-CTM.File = function(stream){
-  this.load(stream);
-};
-
-CTM.File.prototype.load = function(stream){
-  this.header = new CTM.FileHeader(stream);
-
-  this.body = new CTM.FileBody(this.header);
-  
-  this.getReader().read(stream, this.body);
-};
-
-CTM.File.prototype.getReader = function(){
-  var reader;
-
-  switch(this.header.compressionMethod){
-    case CTM.CompressionMethod.RAW:
-      reader = new CTM.ReaderRAW();
-      break;
-    case CTM.CompressionMethod.MG1:
-      reader = new CTM.ReaderMG1();
-      break;
-    case CTM.CompressionMethod.MG2:
-      reader = new CTM.ReaderMG2();
-      break;
-  }
-
-  return reader;
-};
-
-CTM.FileHeader = function(stream){
-  stream.readInt32(); //magic "OCTM"
-  this.fileFormat = stream.readInt32();
-  this.compressionMethod = stream.readInt32();
-  this.vertexCount = stream.readInt32();
-  this.triangleCount = stream.readInt32();
-  this.uvMapCount = stream.readInt32();
-  this.attrMapCount = stream.readInt32();
-  this.flags = stream.readInt32();
-  this.comment = stream.readString();
-};
-
-CTM.FileHeader.prototype.hasNormals = function(){
-  return this.flags & CTM.Flags.NORMALS;
-};
-
-CTM.FileBody = function(header){
-  var i = header.triangleCount * 3,
-      v = header.vertexCount * 3,
-      n = header.hasNormals()? header.vertexCount * 3: 0,
-      u = header.vertexCount * 2,
-      a = header.vertexCount * 4,
-      j = 0;
-
-  var data = new ArrayBuffer(
-    (i + v + n + (u * header.uvMapCount) + (a * header.attrMapCount) ) * 4);
-
-  this.indices = new Uint32Array(data, 0, i);
-
-  this.vertices = new Float32Array(data, i * 4, v);
-
-  if ( header.hasNormals() ){
-    this.normals = new Float32Array(data, (i + v) * 4, n);
-  }
-  
-  if (header.uvMapCount){
-    this.uvMaps = [];
-    for (j = 0; j < header.uvMapCount; ++ j){
-      this.uvMaps[j] = {uv: new Float32Array(data,
-        (i + v + n + (j * u) ) * 4, u) };
-    }
-  }
-  
-  if (header.attrMapCount){
-    this.attrMaps = [];
-    for (j = 0; j < header.attrMapCount; ++ j){
-      this.attrMaps[j] = {attr: new Float32Array(data,
-        (i + v + n + (u * header.uvMapCount) + (j * a) ) * 4, a) };
-    }
-  }
-};
-
-CTM.FileMG2Header = function(stream){
-  stream.readInt32(); //magic "MG2H"
-  this.vertexPrecision = stream.readFloat32();
-  this.normalPrecision = stream.readFloat32();
-  this.lowerBoundx = stream.readFloat32();
-  this.lowerBoundy = stream.readFloat32();
-  this.lowerBoundz = stream.readFloat32();
-  this.higherBoundx = stream.readFloat32();
-  this.higherBoundy = stream.readFloat32();
-  this.higherBoundz = stream.readFloat32();
-  this.divx = stream.readInt32();
-  this.divy = stream.readInt32();
-  this.divz = stream.readInt32();
-  
-  this.sizex = (this.higherBoundx - this.lowerBoundx) / this.divx;
-  this.sizey = (this.higherBoundy - this.lowerBoundy) / this.divy;
-  this.sizez = (this.higherBoundz - this.lowerBoundz) / this.divz;
-};
-
-CTM.ReaderRAW = function(){
-};
-
-CTM.ReaderRAW.prototype.read = function(stream, body){
-  this.readIndices(stream, body.indices);
-  this.readVertices(stream, body.vertices);
-  
-  if (body.normals){
-    this.readNormals(stream, body.normals);
-  }
-  if (body.uvMaps){
-    this.readUVMaps(stream, body.uvMaps);
-  }
-  if (body.attrMaps){
-    this.readAttrMaps(stream, body.attrMaps);
-  }
-};
-
-CTM.ReaderRAW.prototype.readIndices = function(stream, indices){
-  stream.readInt32(); //magic "INDX"
-  stream.readArrayInt32(indices);
-};
-
-CTM.ReaderRAW.prototype.readVertices = function(stream, vertices){
-  stream.readInt32(); //magic "VERT"
-  stream.readArrayFloat32(vertices);
-};
-
-CTM.ReaderRAW.prototype.readNormals = function(stream, normals){
-  stream.readInt32(); //magic "NORM"
-  stream.readArrayFloat32(normals);
-};
-
-CTM.ReaderRAW.prototype.readUVMaps = function(stream, uvMaps){
-  var i = 0;
-  for (; i < uvMaps.length; ++ i){
-    stream.readInt32(); //magic "TEXC"
-
-    uvMaps[i].name = stream.readString();
-    uvMaps[i].filename = stream.readString();
-    stream.readArrayFloat32(uvMaps[i].uv);
-  }
-};
-
-CTM.ReaderRAW.prototype.readAttrMaps = function(stream, attrMaps){
-  var i = 0;
-  for (; i < attrMaps.length; ++ i){
-    stream.readInt32(); //magic "ATTR"
-
-    attrMaps[i].name = stream.readString();
-    stream.readArrayFloat32(attrMaps[i].attr);
-  }
-};
-
-CTM.ReaderMG1 = function(){
-};
-
-CTM.ReaderMG1.prototype.read = function(stream, body){
-  this.readIndices(stream, body.indices);
-  this.readVertices(stream, body.vertices);
-  
-  if (body.normals){
-    this.readNormals(stream, body.normals);
-  }
-  if (body.uvMaps){
-    this.readUVMaps(stream, body.uvMaps);
-  }
-  if (body.attrMaps){
-    this.readAttrMaps(stream, body.attrMaps);
-  }
-};
-
-CTM.ReaderMG1.prototype.readIndices = function(stream, indices){
-  stream.readInt32(); //magic "INDX"
-  stream.readInt32(); //packed size
-  
-  var interleaved = new CTM.InterleavedStream(indices, 3);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-  CTM.restoreIndices(indices, indices.length);
-};
-
-CTM.ReaderMG1.prototype.readVertices = function(stream, vertices){
-  stream.readInt32(); //magic "VERT"
-  stream.readInt32(); //packed size
-  
-  var interleaved = new CTM.InterleavedStream(vertices, 1);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-};
-
-CTM.ReaderMG1.prototype.readNormals = function(stream, normals){
-  stream.readInt32(); //magic "NORM"
-  stream.readInt32(); //packed size
-
-  var interleaved = new CTM.InterleavedStream(normals, 3);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-};
-
-CTM.ReaderMG1.prototype.readUVMaps = function(stream, uvMaps){
-  var i = 0;
-  for (; i < uvMaps.length; ++ i){
-    stream.readInt32(); //magic "TEXC"
-
-    uvMaps[i].name = stream.readString();
-    uvMaps[i].filename = stream.readString();
-    
-    stream.readInt32(); //packed size
-
-    var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
-    LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-  }
-};
-
-CTM.ReaderMG1.prototype.readAttrMaps = function(stream, attrMaps){
-  var i = 0;
-  for (; i < attrMaps.length; ++ i){
-    stream.readInt32(); //magic "ATTR"
-
-    attrMaps[i].name = stream.readString();
-    
-    stream.readInt32(); //packed size
-
-    var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
-    LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-  }
-};
-
-CTM.ReaderMG2 = function(){
-};
-
-CTM.ReaderMG2.prototype.read = function(stream, body){
-  this.MG2Header = new CTM.FileMG2Header(stream);
-  
-  this.readVertices(stream, body.vertices);
-  this.readIndices(stream, body.indices);
-  
-  if (body.normals){
-    this.readNormals(stream, body);
-  }
-  if (body.uvMaps){
-    this.readUVMaps(stream, body.uvMaps);
-  }
-  if (body.attrMaps){
-    this.readAttrMaps(stream, body.attrMaps);
-  }
-};
-
-CTM.ReaderMG2.prototype.readVertices = function(stream, vertices){
-  stream.readInt32(); //magic "VERT"
-  stream.readInt32(); //packed size
-
-  var interleaved = new CTM.InterleavedStream(vertices, 3);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-  
-  var gridIndices = this.readGridIndices(stream, vertices);
-  
-  CTM.restoreVertices(vertices, this.MG2Header, gridIndices, this.MG2Header.vertexPrecision);
-};
-
-CTM.ReaderMG2.prototype.readGridIndices = function(stream, vertices){
-  stream.readInt32(); //magic "GIDX"
-  stream.readInt32(); //packed size
-  
-  var gridIndices = new Uint32Array(vertices.length / 3);
-  
-  var interleaved = new CTM.InterleavedStream(gridIndices, 1);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-  
-  CTM.restoreGridIndices(gridIndices, gridIndices.length);
-  
-  return gridIndices;
-};
-
-CTM.ReaderMG2.prototype.readIndices = function(stream, indices){
-  stream.readInt32(); //magic "INDX"
-  stream.readInt32(); //packed size
-
-  var interleaved = new CTM.InterleavedStream(indices, 3);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-  CTM.restoreIndices(indices, indices.length);
-};
-
-CTM.ReaderMG2.prototype.readNormals = function(stream, body){
-  stream.readInt32(); //magic "NORM"
-  stream.readInt32(); //packed size
-
-  var interleaved = new CTM.InterleavedStream(body.normals, 3);
-  LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-  var smooth = CTM.calcSmoothNormals(body.indices, body.vertices);
-
-  CTM.restoreNormals(body.normals, smooth, this.MG2Header.normalPrecision);
-};
-
-CTM.ReaderMG2.prototype.readUVMaps = function(stream, uvMaps){
-  var i = 0;
-  for (; i < uvMaps.length; ++ i){
-    stream.readInt32(); //magic "TEXC"
-
-    uvMaps[i].name = stream.readString();
-    uvMaps[i].filename = stream.readString();
-    
-    var precision = stream.readFloat32();
-    
-    stream.readInt32(); //packed size
-
-    var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
-    LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-    
-    CTM.restoreMap(uvMaps[i].uv, 2, precision);
-  }
-};
-
-CTM.ReaderMG2.prototype.readAttrMaps = function(stream, attrMaps){
-  var i = 0;
-  for (; i < attrMaps.length; ++ i){
-    stream.readInt32(); //magic "ATTR"
-
-    attrMaps[i].name = stream.readString();
-    
-    var precision = stream.readFloat32();
-    
-    stream.readInt32(); //packed size
-
-    var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
-    LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-    
-    CTM.restoreMap(attrMaps[i].attr, 4, precision);
-  }
-};
-
-CTM.restoreIndices = function(indices, len){
-  var i = 3;
-  if (len > 0){
-    indices[2] += indices[0];
-  }
-  for (; i < len; i += 3){
-    indices[i] += indices[i - 3];
-    
-    if (indices[i] === indices[i - 3]){
-      indices[i + 1] += indices[i - 2];
-    }else{
-      indices[i + 1] += indices[i];
-    }
-
-    indices[i + 2] += indices[i];
-  }
-};
-
-CTM.restoreGridIndices = function(gridIndices, len){
-  var i = 1;
-  for (; i < len; ++ i){
-    gridIndices[i] += gridIndices[i - 1];
-  }
-};
-
-CTM.restoreVertices = function(vertices, grid, gridIndices, precision){
-  var gridIdx, delta, x, y, z,
-      intVertices = new Uint32Array(vertices.buffer, vertices.byteOffset, vertices.length),
-      ydiv = grid.divx, zdiv = ydiv * grid.divy,
-      prevGridIdx = 0x7fffffff, prevDelta = 0,
-      i = 0, j = 0, len = gridIndices.length;
-
-  for (; i < len; j += 3){
-    x = gridIdx = gridIndices[i ++];
-    
-    z = ~~(x / zdiv);
-    x -= ~~(z * zdiv);
-    y = ~~(x / ydiv);
-    x -= ~~(y * ydiv);
-
-    delta = intVertices[j];
-    if (gridIdx === prevGridIdx){
-      delta += prevDelta;
-    }
-
-    vertices[j]     = grid.lowerBoundx +
-      x * grid.sizex + precision * delta;
-    vertices[j + 1] = grid.lowerBoundy +
-      y * grid.sizey + precision * intVertices[j + 1];
-    vertices[j + 2] = grid.lowerBoundz +
-      z * grid.sizez + precision * intVertices[j + 2];
-
-    prevGridIdx = gridIdx;
-    prevDelta = delta;
-  }
-};
-
-CTM.restoreNormals = function(normals, smooth, precision){
-  var ro, phi, theta, sinPhi,
-      nx, ny, nz, by, bz, len,
-      intNormals = new Uint32Array(normals.buffer, normals.byteOffset, normals.length),
-      i = 0, k = normals.length,
-      PI_DIV_2 = 3.141592653589793238462643 * 0.5;
-
-  for (; i < k; i += 3){
-    ro = intNormals[i] * precision;
-    phi = intNormals[i + 1];
-
-    if (phi === 0){
-      normals[i]     = smooth[i]     * ro;
-      normals[i + 1] = smooth[i + 1] * ro;
-      normals[i + 2] = smooth[i + 2] * ro;
-    }else{
-      
-      if (phi <= 4){
-        theta = (intNormals[i + 2] - 2) * PI_DIV_2;
-      }else{
-        theta = ( (intNormals[i + 2] * 4 / phi) - 2) * PI_DIV_2;
-      }
-      
-      phi *= precision * PI_DIV_2;
-      sinPhi = ro * Math.sin(phi);
-
-      nx = sinPhi * Math.cos(theta);
-      ny = sinPhi * Math.sin(theta);
-      nz = ro * Math.cos(phi);
-
-      bz = smooth[i + 1];
-      by = smooth[i] - smooth[i + 2];
-
-      len = Math.sqrt(2 * bz * bz + by * by);
-      if (len > 1e-20){
-        by /= len;
-        bz /= len;
-      }
-
-      normals[i]     = smooth[i]     * nz +
-        (smooth[i + 1] * bz - smooth[i + 2] * by) * ny - bz * nx;
-      normals[i + 1] = smooth[i + 1] * nz -
-        (smooth[i + 2]      + smooth[i]   ) * bz  * ny + by * nx;
-      normals[i + 2] = smooth[i + 2] * nz +
-        (smooth[i]     * by + smooth[i + 1] * bz) * ny + bz * nx;
-    }
-  }
-};
-
-CTM.restoreMap = function(map, count, precision){
-  var delta, value,
-      intMap = new Uint32Array(map.buffer, map.byteOffset, map.length),
-      i = 0, j, len = map.length;
-
-  for (; i < count; ++ i){
-    delta = 0;
-
-    for (j = i; j < len; j += count){
-      value = intMap[j];
-      
-      delta += value & 1? -( (value + 1) >> 1): value >> 1;
-      
-      map[j] = delta * precision;
-    }
-  }
-};
-
-CTM.calcSmoothNormals = function(indices, vertices){
-  var smooth = new Float32Array(vertices.length),
-      indx, indy, indz, nx, ny, nz,
-      v1x, v1y, v1z, v2x, v2y, v2z, len,
-      i, k;
-
-  for (i = 0, k = indices.length; i < k;){
-    indx = indices[i ++] * 3;
-    indy = indices[i ++] * 3;
-    indz = indices[i ++] * 3;
-
-    v1x = vertices[indy]     - vertices[indx];
-    v2x = vertices[indz]     - vertices[indx];
-    v1y = vertices[indy + 1] - vertices[indx + 1];
-    v2y = vertices[indz + 1] - vertices[indx + 1];
-    v1z = vertices[indy + 2] - vertices[indx + 2];
-    v2z = vertices[indz + 2] - vertices[indx + 2];
-    
-    nx = v1y * v2z - v1z * v2y;
-    ny = v1z * v2x - v1x * v2z;
-    nz = v1x * v2y - v1y * v2x;
-    
-    len = Math.sqrt(nx * nx + ny * ny + nz * nz);
-    if (len > 1e-10){
-      nx /= len;
-      ny /= len;
-      nz /= len;
-    }
-    
-    smooth[indx]     += nx;
-    smooth[indx + 1] += ny;
-    smooth[indx + 2] += nz;
-    smooth[indy]     += nx;
-    smooth[indy + 1] += ny;
-    smooth[indy + 2] += nz;
-    smooth[indz]     += nx;
-    smooth[indz + 1] += ny;
-    smooth[indz + 2] += nz;
-  }
-
-  for (i = 0, k = smooth.length; i < k; i += 3){
-    len = Math.sqrt(smooth[i] * smooth[i] + 
-      smooth[i + 1] * smooth[i + 1] +
-      smooth[i + 2] * smooth[i + 2]);
-
-    if(len > 1e-10){
-      smooth[i]     /= len;
-      smooth[i + 1] /= len;
-      smooth[i + 2] /= len;
-    }
-  }
-
-  return smooth;
-};
-
-CTM.isLittleEndian = (function(){
-  var buffer = new ArrayBuffer(2),
-      bytes = new Uint8Array(buffer),
-      ints = new Uint16Array(buffer);
-
-  bytes[0] = 1;
-
-  return ints[0] === 1;
-}());
-
-CTM.InterleavedStream = function(data, count){
-  this.data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
-  this.offset = CTM.isLittleEndian? 3: 0;
-  this.count = count * 4;
-  this.len = this.data.length;
-};
-
-CTM.InterleavedStream.prototype.writeByte = function(value){
-  this.data[this.offset] = value;
-  
-  this.offset += this.count;
-  if (this.offset >= this.len){
-  
-    this.offset -= this.len - 4;
-    if (this.offset >= this.count){
-    
-      this.offset -= this.count + (CTM.isLittleEndian? 1: -1);
-    }
-  }
-};
-
-CTM.Stream = function(data){
-  this.data = data;
-  this.offset = 0;
-};
-
-CTM.Stream.prototype.TWO_POW_MINUS23 = Math.pow(2, -23);
-
-CTM.Stream.prototype.TWO_POW_MINUS126 = Math.pow(2, -126);
-
-CTM.Stream.prototype.readByte = function(){
-  return this.data.charCodeAt(this.offset ++) & 0xff;
-};
-
-CTM.Stream.prototype.readInt32 = function(){
-  var i = this.readByte();
-  i |= this.readByte() << 8;
-  i |= this.readByte() << 16;
-  return i | (this.readByte() << 24);
-};
-
-CTM.Stream.prototype.readFloat32 = function(){
-  var m = this.readByte();
-  m += this.readByte() << 8;
-
-  var b1 = this.readByte();
-  var b2 = this.readByte();
-
-  m += (b1 & 0x7f) << 16; 
-  var e = ( (b2 & 0x7f) << 1) | ( (b1 & 0x80) >>> 7);
-  var s = b2 & 0x80? -1: 1;
-
-  if (e === 255){
-    return m !== 0? NaN: s * Infinity;
-  }
-  if (e > 0){
-    return s * (1 + (m * this.TWO_POW_MINUS23) ) * Math.pow(2, e - 127);
-  }
-  if (m !== 0){
-    return s * m * this.TWO_POW_MINUS126;
-  }
-  return s * 0;
-};
-
-CTM.Stream.prototype.readString = function(){
-  var len = this.readInt32();
-
-  this.offset += len;
-
-  return this.data.substr(this.offset - len, len);
-};
-
-CTM.Stream.prototype.readArrayInt32 = function(array){
-  var i = 0, len = array.length;
-  
-  while(i < len){
-    array[i ++] = this.readInt32();
-  }
-
-  return array;
-};
-
-CTM.Stream.prototype.readArrayFloat32 = function(array){
-  var i = 0, len = array.length;
-
-  while(i < len){
-    array[i ++] = this.readFloat32();
-  }
-
-  return array;
-};
diff --git a/emperor/support_files/js/js/ctm/license/OpenCTM.txt b/emperor/support_files/js/js/ctm/license/OpenCTM.txt
deleted file mode 100644
index 0e66fa7..0000000
--- a/emperor/support_files/js/js/ctm/license/OpenCTM.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2009-2010 Marcus Geelnard
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-    1. The origin of this software must not be misrepresented; you must not
-    claim that you wrote the original software. If you use this software
-    in a product, an acknowledgment in the product documentation would be
-    appreciated but is not required.
-
-    2. Altered source versions must be plainly marked as such, and must not
-    be misrepresented as being the original software.
-
-    3. This notice may not be removed or altered from any source
-    distribution.
diff --git a/emperor/support_files/js/js/ctm/license/js-openctm.txt b/emperor/support_files/js/js/ctm/license/js-openctm.txt
deleted file mode 100644
index 8abd005..0000000
--- a/emperor/support_files/js/js/ctm/license/js-openctm.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2011 Juan Mellado
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/emperor/support_files/js/js/ctm/lzma.js b/emperor/support_files/js/js/ctm/lzma.js
deleted file mode 100644
index d5c5db3..0000000
--- a/emperor/support_files/js/js/ctm/lzma.js
+++ /dev/null
@@ -1,510 +0,0 @@
-
-var LZMA = LZMA || {};
-
-LZMA.OutWindow = function(){
-  this._windowSize = 0;
-};
-
-LZMA.OutWindow.prototype.create = function(windowSize){
-  if ( (!this._buffer) || (this._windowSize !== windowSize) ){
-    this._buffer = [];
-  }
-  this._windowSize = windowSize;
-  this._pos = 0;
-  this._streamPos = 0;
-};
-
-LZMA.OutWindow.prototype.flush = function(){
-  var size = this._pos - this._streamPos;
-  if (size !== 0){
-    while(size --){
-      this._stream.writeByte(this._buffer[this._streamPos ++]);
-    }
-    if (this._pos >= this._windowSize){
-      this._pos = 0;
-    }
-    this._streamPos = this._pos;
-  }
-};
-
-LZMA.OutWindow.prototype.releaseStream = function(){
-  this.flush();
-  this._stream = null;
-};
-
-LZMA.OutWindow.prototype.setStream = function(stream){
-  this.releaseStream();
-  this._stream = stream;
-};
-
-LZMA.OutWindow.prototype.init = function(solid){
-  if (!solid){
-    this._streamPos = 0;
-    this._pos = 0;
-  }
-};
-
-LZMA.OutWindow.prototype.copyBlock = function(distance, len){
-  var pos = this._pos - distance - 1;
-  if (pos < 0){
-    pos += this._windowSize;
-  }
-  while(len --){
-    if (pos >= this._windowSize){
-      pos = 0;
-    }
-    this._buffer[this._pos ++] = this._buffer[pos ++];
-    if (this._pos >= this._windowSize){
-      this.flush();
-    }
-  }
-};
-
-LZMA.OutWindow.prototype.putByte = function(b){
-  this._buffer[this._pos ++] = b;
-  if (this._pos >= this._windowSize){
-    this.flush();
-  }
-};
-
-LZMA.OutWindow.prototype.getByte = function(distance){
-  var pos = this._pos - distance - 1;
-  if (pos < 0){
-    pos += this._windowSize;
-  }
-  return this._buffer[pos];
-};
-
-LZMA.RangeDecoder = function(){
-};
-
-LZMA.RangeDecoder.prototype.setStream = function(stream){
-  this._stream = stream;
-};
-
-LZMA.RangeDecoder.prototype.releaseStream = function(){
-  this._stream = null;
-};
-
-LZMA.RangeDecoder.prototype.init = function(){
-  var i = 5;
-
-  this._code = 0;
-  this._range = -1;
-  
-  while(i --){
-    this._code = (this._code << 8) | this._stream.readByte();
-  }
-};
-
-LZMA.RangeDecoder.prototype.decodeDirectBits = function(numTotalBits){
-  var result = 0, i = numTotalBits, t;
-
-  while(i --){
-    this._range >>>= 1;
-    t = (this._code - this._range) >>> 31;
-    this._code -= this._range & (t - 1);
-    result = (result << 1) | (1 - t);
-
-    if ( (this._range & 0xff000000) === 0){
-      this._code = (this._code << 8) | this._stream.readByte();
-      this._range <<= 8;
-    }
-  }
-
-  return result;
-};
-
-LZMA.RangeDecoder.prototype.decodeBit = function(probs, index){
-  var prob = probs[index],
-      newBound = (this._range >>> 11) * prob;
-
-  if ( (this._code ^ 0x80000000) < (newBound ^ 0x80000000) ){
-    this._range = newBound;
-    probs[index] += (2048 - prob) >>> 5;
-    if ( (this._range & 0xff000000) === 0){
-      this._code = (this._code << 8) | this._stream.readByte();
-      this._range <<= 8;
-    }
-    return 0;
-  }
-
-  this._range -= newBound;
-  this._code -= newBound;
-  probs[index] -= prob >>> 5;
-  if ( (this._range & 0xff000000) === 0){
-    this._code = (this._code << 8) | this._stream.readByte();
-    this._range <<= 8;
-  }
-  return 1;
-};
-
-LZMA.initBitModels = function(probs, len){
-  while(len --){
-    probs[len] = 1024;
-  }
-};
-
-LZMA.BitTreeDecoder = function(numBitLevels){
-  this._models = [];
-  this._numBitLevels = numBitLevels;
-};
-
-LZMA.BitTreeDecoder.prototype.init = function(){
-  LZMA.initBitModels(this._models, 1 << this._numBitLevels);
-};
-
-LZMA.BitTreeDecoder.prototype.decode = function(rangeDecoder){
-  var m = 1, i = this._numBitLevels;
-
-  while(i --){
-    m = (m << 1) | rangeDecoder.decodeBit(this._models, m);
-  }
-  return m - (1 << this._numBitLevels);
-};
-
-LZMA.BitTreeDecoder.prototype.reverseDecode = function(rangeDecoder){
-  var m = 1, symbol = 0, i = 0, bit;
-
-  for (; i < this._numBitLevels; ++ i){
-    bit = rangeDecoder.decodeBit(this._models, m);
-    m = (m << 1) | bit;
-    symbol |= bit << i;
-  }
-  return symbol;
-};
-
-LZMA.reverseDecode2 = function(models, startIndex, rangeDecoder, numBitLevels){
-  var m = 1, symbol = 0, i = 0, bit;
-
-  for (; i < numBitLevels; ++ i){
-    bit = rangeDecoder.decodeBit(models, startIndex + m);
-    m = (m << 1) | bit;
-    symbol |= bit << i;
-  }
-  return symbol;
-};
-
-LZMA.LenDecoder = function(){
-  this._choice = [];
-  this._lowCoder = [];
-  this._midCoder = [];
-  this._highCoder = new LZMA.BitTreeDecoder(8);
-  this._numPosStates = 0;
-};
-
-LZMA.LenDecoder.prototype.create = function(numPosStates){
-  for (; this._numPosStates < numPosStates; ++ this._numPosStates){
-    this._lowCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
-    this._midCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
-  }
-};
-
-LZMA.LenDecoder.prototype.init = function(){
-  var i = this._numPosStates;
-  LZMA.initBitModels(this._choice, 2);
-  while(i --){
-    this._lowCoder[i].init();
-    this._midCoder[i].init();
-  }
-  this._highCoder.init();
-};
-
-LZMA.LenDecoder.prototype.decode = function(rangeDecoder, posState){
-  if (rangeDecoder.decodeBit(this._choice, 0) === 0){
-    return this._lowCoder[posState].decode(rangeDecoder);
-  }
-  if (rangeDecoder.decodeBit(this._choice, 1) === 0){
-    return 8 + this._midCoder[posState].decode(rangeDecoder);
-  }
-  return 16 + this._highCoder.decode(rangeDecoder);
-};
-
-LZMA.Decoder2 = function(){
-  this._decoders = [];
-};
-
-LZMA.Decoder2.prototype.init = function(){
-  LZMA.initBitModels(this._decoders, 0x300);
-};
-
-LZMA.Decoder2.prototype.decodeNormal = function(rangeDecoder){
-  var symbol = 1;
-
-  do{
-    symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
-  }while(symbol < 0x100);
-
-  return symbol & 0xff;
-};
-
-LZMA.Decoder2.prototype.decodeWithMatchByte = function(rangeDecoder, matchByte){
-  var symbol = 1, matchBit, bit;
-
-  do{
-    matchBit = (matchByte >> 7) & 1;
-    matchByte <<= 1;
-    bit = rangeDecoder.decodeBit(this._decoders, ( (1 + matchBit) << 8) + symbol);
-    symbol = (symbol << 1) | bit;
-    if (matchBit !== bit){
-      while(symbol < 0x100){
-        symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
-      }
-      break;
-    }
-  }while(symbol < 0x100);
-
-  return symbol & 0xff;
-};
-
-LZMA.LiteralDecoder = function(){
-};
-
-LZMA.LiteralDecoder.prototype.create = function(numPosBits, numPrevBits){
-  var i;
-
-  if (this._coders
-    && (this._numPrevBits === numPrevBits)
-    && (this._numPosBits === numPosBits) ){
-    return;
-  }
-  this._numPosBits = numPosBits;
-  this._posMask = (1 << numPosBits) - 1;
-  this._numPrevBits = numPrevBits;
-
-  this._coders = [];
-
-  i = 1 << (this._numPrevBits + this._numPosBits);
-  while(i --){
-    this._coders[i] = new LZMA.Decoder2();
-  }
-};
-
-LZMA.LiteralDecoder.prototype.init = function(){
-  var i = 1 << (this._numPrevBits + this._numPosBits);
-  while(i --){
-    this._coders[i].init();
-  }
-};
-
-LZMA.LiteralDecoder.prototype.getDecoder = function(pos, prevByte){
-  return this._coders[( (pos & this._posMask) << this._numPrevBits)
-    + ( (prevByte & 0xff) >>> (8 - this._numPrevBits) )];
-};
-
-LZMA.Decoder = function(){
-  this._outWindow = new LZMA.OutWindow();
-  this._rangeDecoder = new LZMA.RangeDecoder();
-  this._isMatchDecoders = [];
-  this._isRepDecoders = [];
-  this._isRepG0Decoders = [];
-  this._isRepG1Decoders = [];
-  this._isRepG2Decoders = [];
-  this._isRep0LongDecoders = [];
-  this._posSlotDecoder = [];
-  this._posDecoders = [];
-  this._posAlignDecoder = new LZMA.BitTreeDecoder(4);
-  this._lenDecoder = new LZMA.LenDecoder();
-  this._repLenDecoder = new LZMA.LenDecoder();
-  this._literalDecoder = new LZMA.LiteralDecoder();
-  this._dictionarySize = -1;
-  this._dictionarySizeCheck = -1;
-
-  this._posSlotDecoder[0] = new LZMA.BitTreeDecoder(6);
-  this._posSlotDecoder[1] = new LZMA.BitTreeDecoder(6);
-  this._posSlotDecoder[2] = new LZMA.BitTreeDecoder(6);
-  this._posSlotDecoder[3] = new LZMA.BitTreeDecoder(6);
-};
-
-LZMA.Decoder.prototype.setDictionarySize = function(dictionarySize){
-  if (dictionarySize < 0){
-    return false;
-  }
-  if (this._dictionarySize !== dictionarySize){
-    this._dictionarySize = dictionarySize;
-    this._dictionarySizeCheck = Math.max(this._dictionarySize, 1);
-    this._outWindow.create( Math.max(this._dictionarySizeCheck, 4096) );
-  }
-  return true;
-};
-
-LZMA.Decoder.prototype.setLcLpPb = function(lc, lp, pb){
-  var numPosStates = 1 << pb;
-
-  if (lc > 8 || lp > 4 || pb > 4){
-    return false;
-  }
-
-  this._literalDecoder.create(lp, lc);
-
-  this._lenDecoder.create(numPosStates);
-  this._repLenDecoder.create(numPosStates);
-  this._posStateMask = numPosStates - 1;
-
-  return true;
-};
-
-LZMA.Decoder.prototype.init = function(){
-  var i = 4;
-
-  this._outWindow.init(false);
-
-  LZMA.initBitModels(this._isMatchDecoders, 192);
-  LZMA.initBitModels(this._isRep0LongDecoders, 192);
-  LZMA.initBitModels(this._isRepDecoders, 12);
-  LZMA.initBitModels(this._isRepG0Decoders, 12);
-  LZMA.initBitModels(this._isRepG1Decoders, 12);
-  LZMA.initBitModels(this._isRepG2Decoders, 12);
-  LZMA.initBitModels(this._posDecoders, 114);
-
-  this._literalDecoder.init();
-
-  while(i --){
-    this._posSlotDecoder[i].init();
-  }
-
-  this._lenDecoder.init();
-  this._repLenDecoder.init();
-  this._posAlignDecoder.init();
-  this._rangeDecoder.init();
-};
-
-LZMA.Decoder.prototype.decode = function(inStream, outStream, outSize){
-  var state = 0, rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0, nowPos64 = 0, prevByte = 0,
-      posState, decoder2, len, distance, posSlot, numDirectBits;
-
-  this._rangeDecoder.setStream(inStream);
-  this._outWindow.setStream(outStream);
-
-  this.init();
-
-  while(outSize < 0 || nowPos64 < outSize){
-    posState = nowPos64 & this._posStateMask;
-
-    if (this._rangeDecoder.decodeBit(this._isMatchDecoders, (state << 4) + posState) === 0){
-      decoder2 = this._literalDecoder.getDecoder(nowPos64 ++, prevByte);
-
-      if (state >= 7){
-        prevByte = decoder2.decodeWithMatchByte(this._rangeDecoder, this._outWindow.getByte(rep0) );
-      }else{
-        prevByte = decoder2.decodeNormal(this._rangeDecoder);
-      }
-      this._outWindow.putByte(prevByte);
-
-      state = state < 4? 0: state - (state < 10? 3: 6);
-
-    }else{
-
-      if (this._rangeDecoder.decodeBit(this._isRepDecoders, state) === 1){
-        len = 0;
-        if (this._rangeDecoder.decodeBit(this._isRepG0Decoders, state) === 0){
-          if (this._rangeDecoder.decodeBit(this._isRep0LongDecoders, (state << 4) + posState) === 0){
-            state = state < 7? 9: 11;
-            len = 1;
-          }
-        }else{
-          if (this._rangeDecoder.decodeBit(this._isRepG1Decoders, state) === 0){
-            distance = rep1;
-          }else{
-            if (this._rangeDecoder.decodeBit(this._isRepG2Decoders, state) === 0){
-              distance = rep2;
-            }else{
-              distance = rep3;
-              rep3 = rep2;
-            }
-            rep2 = rep1;
-          }
-          rep1 = rep0;
-          rep0 = distance;
-        }
-        if (len === 0){
-          len = 2 + this._repLenDecoder.decode(this._rangeDecoder, posState);
-          state = state < 7? 8: 11;
-        }
-      }else{
-        rep3 = rep2;
-        rep2 = rep1;
-        rep1 = rep0;
-
-        len = 2 + this._lenDecoder.decode(this._rangeDecoder, posState);
-        state = state < 7? 7: 10;
-
-        posSlot = this._posSlotDecoder[len <= 5? len - 2: 3].decode(this._rangeDecoder);
-        if (posSlot >= 4){
-
-          numDirectBits = (posSlot >> 1) - 1;
-          rep0 = (2 | (posSlot & 1) ) << numDirectBits;
-
-          if (posSlot < 14){
-            rep0 += LZMA.reverseDecode2(this._posDecoders,
-                rep0 - posSlot - 1, this._rangeDecoder, numDirectBits);
-          }else{
-            rep0 += this._rangeDecoder.decodeDirectBits(numDirectBits - 4) << 4;
-            rep0 += this._posAlignDecoder.reverseDecode(this._rangeDecoder);
-            if (rep0 < 0){
-              if (rep0 === -1){
-                break;
-              }
-              return false;
-            }
-          }
-        }else{
-          rep0 = posSlot;
-        }
-      }
-
-      if (rep0 >= nowPos64 || rep0 >= this._dictionarySizeCheck){
-        return false;
-      }
-
-      this._outWindow.copyBlock(rep0, len);
-      nowPos64 += len;
-      prevByte = this._outWindow.getByte(0);
-    }
-  }
-
-  this._outWindow.flush();
-  this._outWindow.releaseStream();
-  this._rangeDecoder.releaseStream();
-
-  return true;
-};
-
-LZMA.Decoder.prototype.setDecoderProperties = function(properties){
-  var value, lc, lp, pb, dictionarySize;
-
-  if (properties.size < 5){
-    return false;
-  }
-
-  value = properties.readByte();
-  lc = value % 9;
-  value = ~~(value / 9);
-  lp = value % 5;
-  pb = ~~(value / 5);
-
-  if ( !this.setLcLpPb(lc, lp, pb) ){
-    return false;
-  }
-
-  dictionarySize = properties.readByte();
-  dictionarySize |= properties.readByte() << 8;
-  dictionarySize |= properties.readByte() << 16;
-  dictionarySize += properties.readByte() * 16777216;
-
-  return this.setDictionarySize(dictionarySize);
-};
-
-LZMA.decompress = function(properties, inStream, outStream, outSize){
-  var decoder = new LZMA.Decoder();
-
-  if ( !decoder.setDecoderProperties(properties) ){
-    throw "Incorrect stream properties";
-  }
-
-  if ( !decoder.decode(inStream, outStream, outSize) ){
-    throw "Error in data stream";
-  }
-
-  return true;
-};
diff --git a/emperor/support_files/js/js/postprocessing/BloomPass.js b/emperor/support_files/js/js/postprocessing/BloomPass.js
deleted file mode 100644
index ca2de01..0000000
--- a/emperor/support_files/js/js/postprocessing/BloomPass.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.BloomPass = function( strength, kernelSize, sigma, resolution ) {
-
-	strength = ( strength !== undefined ) ? strength : 1;
-	kernelSize = ( kernelSize !== undefined ) ? kernelSize : 25;
-	sigma = ( sigma !== undefined ) ? sigma : 4.0;
-	resolution = ( resolution !== undefined ) ? resolution : 256;
-
-	// render targets
-
-	var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat };
-
-	this.renderTargetX = new THREE.WebGLRenderTarget( resolution, resolution, pars );
-	this.renderTargetY = new THREE.WebGLRenderTarget( resolution, resolution, pars );
-
-	// screen material
-
-	var screenShader = THREE.ShaderExtras[ "screen" ];
-
-	this.screenUniforms = THREE.UniformsUtils.clone( screenShader.uniforms );
-
-	this.screenUniforms[ "opacity" ].value = strength;
-
-	this.materialScreen = new THREE.ShaderMaterial( {
-
-		uniforms: this.screenUniforms,
-		vertexShader: screenShader.vertexShader,
-		fragmentShader: screenShader.fragmentShader,
-		blending: THREE.AdditiveBlending,
-		transparent: true
-
-	} );
-
-	// convolution material
-
-	var convolutionShader = THREE.ShaderExtras[ "convolution" ];
-
-	this.convolutionUniforms = THREE.UniformsUtils.clone( convolutionShader.uniforms );
-
-	this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurx;
-	this.convolutionUniforms[ "cKernel" ].value = THREE.ShaderExtras.buildKernel( sigma );
-
-	this.materialConvolution = new THREE.ShaderMaterial( {
-
-		uniforms: this.convolutionUniforms,
-		vertexShader:   "#define KERNEL_SIZE " + kernelSize + ".0\n" + convolutionShader.vertexShader,
-		fragmentShader: "#define KERNEL_SIZE " + kernelSize + "\n"   + convolutionShader.fragmentShader
-
-	} );
-
-	this.enabled = true;
-	this.needsSwap = false;
-	this.clear = false;
-
-};
-
-THREE.BloomPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
-
-		if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
-
-		// Render quad with blured scene into texture (convolution pass 1)
-
-		THREE.EffectComposer.quad.material = this.materialConvolution;
-
-		this.convolutionUniforms[ "tDiffuse" ].texture = readBuffer;
-		this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX;
-
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetX, true );
-
-
-		// Render quad with blured scene into texture (convolution pass 2)
-
-		this.convolutionUniforms[ "tDiffuse" ].texture = this.renderTargetX;
-		this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurY;
-
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetY, true );
-
-		// Render original scene with superimposed blur to texture
-
-		THREE.EffectComposer.quad.material = this.materialScreen;
-
-		this.screenUniforms[ "tDiffuse" ].texture = this.renderTargetY;
-
-		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
-
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer, this.clear );
-
-	}
-
-};
-
-THREE.BloomPass.blurX = new THREE.Vector2( 0.001953125, 0.0 );
-THREE.BloomPass.blurY = new THREE.Vector2( 0.0, 0.001953125 );
-
-
diff --git a/emperor/support_files/js/js/postprocessing/DotScreenPass.js b/emperor/support_files/js/js/postprocessing/DotScreenPass.js
deleted file mode 100644
index 0cafe26..0000000
--- a/emperor/support_files/js/js/postprocessing/DotScreenPass.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.DotScreenPass = function( center, angle, scale ) {
-
-	var shader = THREE.ShaderExtras[ "dotscreen" ];
-
-	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-	if ( center !== undefined )
-		this.uniforms[ "center" ].value.copy( center );
-
-	if ( angle !== undefined )	this.uniforms[ "angle"].value = angle;
-	if ( scale !== undefined )	this.uniforms[ "scale"].value = scale;
-
-	this.material = new THREE.ShaderMaterial( {
-
-		uniforms: this.uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-
-	} );
-
-	this.enabled = true;
-	this.renderToScreen = false;
-	this.needsSwap = true;
-
-};
-
-THREE.DotScreenPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		this.uniforms[ "tDiffuse" ].texture = readBuffer;
-		this.uniforms[ "tSize" ].value.set( readBuffer.width, readBuffer.height );
-
-		THREE.EffectComposer.quad.material = this.material;
-
-		if ( this.renderToScreen ) {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera );
-
-		} else {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, false );
-
-		}
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/EffectComposer.js b/emperor/support_files/js/js/postprocessing/EffectComposer.js
deleted file mode 100644
index 25ed074..0000000
--- a/emperor/support_files/js/js/postprocessing/EffectComposer.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.EffectComposer = function( renderer, renderTarget ) {
-
-	this.renderer = renderer;
-
-	this.renderTarget1 = renderTarget;
-
-	if ( this.renderTarget1 === undefined ) {
-
-		this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBufer: false };
-		this.renderTarget1 = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters );
-
-	}
-
-	this.renderTarget2 = this.renderTarget1.clone();
-
-	this.writeBuffer = this.renderTarget1;
-	this.readBuffer = this.renderTarget2;
-
-	this.passes = [];
-
-	this.copyPass = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
-
-};
-
-THREE.EffectComposer.prototype = {
-
-	swapBuffers: function() {
-
-		var tmp = this.readBuffer;
-		this.readBuffer = this.writeBuffer;
-		this.writeBuffer = tmp;
-
-	},
-
-	addPass: function ( pass ) {
-
-		this.passes.push( pass );
-
-	},
-
-	render: function ( delta ) {
-
-		this.writeBuffer = this.renderTarget1;
-		this.readBuffer = this.renderTarget2;
-
-		var maskActive = false;
-
-		var pass, i, il = this.passes.length;
-
-		for ( i = 0; i < il; i ++ ) {
-
-			pass = this.passes[ i ];
-
-			if ( !pass.enabled ) continue;
-
-			pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );
-
-			if ( pass.needsSwap ) {
-
-				if ( maskActive ) {
-
-					var context = this.renderer.context;
-
-					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
-
-					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
-
-					context.stencilFunc( context.EQUAL, 1, 0xffffffff );
-
-				}
-
-				this.swapBuffers();
-
-			}
-
-			if ( pass instanceof THREE.MaskPass ) {
-
-				maskActive = true;
-
-			} else if ( pass instanceof THREE.ClearMaskPass ) {
-
-				maskActive = false;
-
-			}
-
-		}
-
-	},
-
-	reset: function ( renderTarget ) {
-
-		this.renderTarget1 = renderTarget;
-
-		if ( this.renderTarget1 === undefined ) {
-
-			this.renderTarget1 = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters );
-
-		}
-
-		this.renderTarget2 = this.renderTarget1.clone();
-
-		this.writeBuffer = this.renderTarget1;
-		this.readBuffer = this.renderTarget2;
-
-		THREE.EffectComposer.quad.scale.set( window.innerWidth, window.innerHeight, 1 );
-
-		THREE.EffectComposer.camera.left = window.innerWidth / - 2;
-		THREE.EffectComposer.camera.right = window.innerWidth / 2;
-		THREE.EffectComposer.camera.top = window.innerHeight / 2;
-		THREE.EffectComposer.camera.bottom = window.innerHeight / - 2;
-
-		THREE.EffectComposer.camera.updateProjectionMatrix();
-
-	}
-
-};
-
-// shared ortho camera
-
-THREE.EffectComposer.camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -10000, 10000 );
-
-// shared fullscreen quad scene
-
-THREE.EffectComposer.geometry = new THREE.PlaneGeometry( 1, 1 );
-
-THREE.EffectComposer.quad = new THREE.Mesh( THREE.EffectComposer.geometry, null );
-THREE.EffectComposer.quad.position.z = -100;
-THREE.EffectComposer.quad.scale.set( window.innerWidth, window.innerHeight, 1 );
-
-THREE.EffectComposer.scene = new THREE.Scene();
-THREE.EffectComposer.scene.add( THREE.EffectComposer.quad );
-THREE.EffectComposer.scene.add( THREE.EffectComposer.camera );
diff --git a/emperor/support_files/js/js/postprocessing/FilmPass.js b/emperor/support_files/js/js/postprocessing/FilmPass.js
deleted file mode 100644
index 3ff6884..0000000
--- a/emperor/support_files/js/js/postprocessing/FilmPass.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.FilmPass = function( noiseIntensity, scanlinesIntensity, scanlinesCount, grayscale ) {
-
-	var shader = THREE.ShaderExtras[ "film" ];
-
-	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-	this.material = new THREE.ShaderMaterial( {
-
-		uniforms: this.uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-
-	} );
-
-	if ( grayscale !== undefined )	this.uniforms.grayscale.value = grayscale;
-	if ( noiseIntensity !== undefined ) this.uniforms.nIntensity.value = noiseIntensity;
-	if ( scanlinesIntensity !== undefined ) this.uniforms.sIntensity.value = scanlinesIntensity;
-	if ( scanlinesCount !== undefined ) this.uniforms.sCount.value = scanlinesCount;
-
-	this.enabled = true;
-	this.renderToScreen = false;
-	this.needsSwap = true;
-
-};
-
-THREE.FilmPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		this.uniforms[ "tDiffuse" ].texture = readBuffer;
-		this.uniforms[ "time" ].value += delta;
-
-		THREE.EffectComposer.quad.material = this.material;
-
-		if ( this.renderToScreen ) {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera );
-
-		} else {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, false );
-
-		}
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/MaskPass.js b/emperor/support_files/js/js/postprocessing/MaskPass.js
deleted file mode 100644
index 23238b0..0000000
--- a/emperor/support_files/js/js/postprocessing/MaskPass.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.MaskPass = function ( scene, camera ) {
-
-	this.scene = scene;
-	this.camera = camera;
-
-	this.enabled = true;
-	this.clear = true;
-	this.needsSwap = false;
-
-	this.inverse = false;
-
-};
-
-THREE.MaskPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		var context = renderer.context;
-
-		// don't update color or depth
-
-		context.colorMask( false, false, false, false );
-		context.depthMask( false );
-
-		// set up stencil
-
-		var writeValue, clearValue;
-
-		if ( this.inverse ) {
-
-			writeValue = 0;
-			clearValue = 1;
-
-		} else {
-
-			writeValue = 1;
-			clearValue = 0;
-
-		}
-
-		context.enable( context.STENCIL_TEST );
-		context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE );
-		context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff );
-		context.clearStencil( clearValue );
-
-		// draw into the stencil buffer
-
-		renderer.render( this.scene, this.camera, readBuffer, this.clear );
-		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
-
-		// re-enable update of color and depth
-
-		context.colorMask( true, true, true, true );
-		context.depthMask( true );
-
-		// only render where stencil is set to 1
-
-		context.stencilFunc( context.EQUAL, 1, 0xffffffff );  // draw if == 1
-		context.stencilOp( context.KEEP, context.KEEP, context.KEEP );
-
-	}
-
-};
-
-
-THREE.ClearMaskPass = function () {
-
-	this.enabled = true;
-
-};
-
-THREE.ClearMaskPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		var context = renderer.context;
-
-		context.disable( context.STENCIL_TEST );
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/RenderPass.js b/emperor/support_files/js/js/postprocessing/RenderPass.js
deleted file mode 100644
index 0dcc13f..0000000
--- a/emperor/support_files/js/js/postprocessing/RenderPass.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
-
-	this.scene = scene;
-	this.camera = camera;
-
-	this.overrideMaterial = overrideMaterial;
-
-	this.clearColor = clearColor;
-	this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1;
-
-	this.oldClearColor = new THREE.Color();
-	this.oldClearAlpha = 1;
-
-	this.enabled = true;
-	this.clear = true;
-	this.needsSwap = false;
-
-};
-
-THREE.RenderPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		this.scene.overrideMaterial = this.overrideMaterial;
-
-		if ( this.clearColor ) {
-
-			this.oldClearColor.copy( renderer.getClearColor() );
-			this.oldClearAlpha = renderer.getClearAlpha();
-
-			renderer.setClearColor( this.clearColor, this.clearAlpha );
-
-		}
-
-		renderer.render( this.scene, this.camera, readBuffer, this.clear );
-
-		if ( this.clearColor ) {
-
-			renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
-
-		}
-
-		this.scene.overrideMaterial = null;
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/SavePass.js b/emperor/support_files/js/js/postprocessing/SavePass.js
deleted file mode 100644
index ea4478f..0000000
--- a/emperor/support_files/js/js/postprocessing/SavePass.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SavePass = function( renderTarget ) {
-
-	var shader = THREE.ShaderExtras[ "screen" ];
-
-	this.textureID = "tDiffuse";
-
-	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-	this.material = new THREE.ShaderMaterial( {
-
-		uniforms: this.uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-
-	} );
-
-	this.renderTarget = renderTarget;
-
-	if ( this.renderTarget === undefined ) {
-
-		this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBufer: false };
-		this.renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters );
-
-	}
-
-	this.enabled = true;
-	this.needsSwap = false;
-	this.clear = false;
-
-};
-
-THREE.SavePass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		if ( this.uniforms[ this.textureID ] ) {
-
-			this.uniforms[ this.textureID ].texture = readBuffer;
-
-		}
-
-		THREE.EffectComposer.quad.material = this.material;
-
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTarget, this.clear );
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/ShaderPass.js b/emperor/support_files/js/js/postprocessing/ShaderPass.js
deleted file mode 100644
index 13c9e75..0000000
--- a/emperor/support_files/js/js/postprocessing/ShaderPass.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.ShaderPass = function( shader, textureID ) {
-
-	this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
-
-	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-	this.material = new THREE.ShaderMaterial( {
-
-		uniforms: this.uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-
-	} );
-
-	this.renderToScreen = false;
-
-	this.enabled = true;
-	this.needsSwap = true;
-	this.clear = false;
-
-};
-
-THREE.ShaderPass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		if ( this.uniforms[ this.textureID ] ) {
-
-			this.uniforms[ this.textureID ].texture = readBuffer;
-
-		}
-
-		THREE.EffectComposer.quad.material = this.material;
-
-		if ( this.renderToScreen ) {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera );
-
-		} else {
-
-			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, this.clear );
-
-		}
-
-	}
-
-};
diff --git a/emperor/support_files/js/js/postprocessing/TexturePass.js b/emperor/support_files/js/js/postprocessing/TexturePass.js
deleted file mode 100644
index e0fb138..0000000
--- a/emperor/support_files/js/js/postprocessing/TexturePass.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.TexturePass = function( texture, opacity ) {
-
-	var shader = THREE.ShaderExtras[ "screen" ];
-
-	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-	this.uniforms[ "opacity" ].value = ( opacity !== undefined ) ? opacity : 1.0;
-	this.uniforms[ "tDiffuse" ].texture = texture;
-
-	this.material = new THREE.ShaderMaterial( {
-
-		uniforms: this.uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-
-	} );
-
-	this.enabled = true;
-	this.needsSwap = false;
-
-};
-
-THREE.TexturePass.prototype = {
-
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		THREE.EffectComposer.quad.material = this.material;
-
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer );
-
-	}
-
-};
diff --git a/emperor/support_files/js/model.js b/emperor/support_files/js/model.js
new file mode 100644
index 0000000..e9c2a14
--- /dev/null
+++ b/emperor/support_files/js/model.js
@@ -0,0 +1,380 @@
+define([
+    'jquery',
+    'underscore'
+],
+function($, _) {
+  /**
+   *
+   * @class Plottable
+   *
+   * Represents a sample and the associated metadata in the ordination space.
+   *
+   * @param {string} name A string indicating the name of the sample.
+   * @param {string[]} metadata An Array of strings with the metadata values.
+   * @param {float[]} coordinates An Array of floats indicating the position in
+   * space where this sample is located.
+   * @param {integer} [idx = -1] An integer representing the index where the
+   * object is located in a DecompositionModel.
+   * @param {float[]} [ci = []] An array of floats indicating the confidence
+   * intervals in each dimension.
+   *
+   * @return {Plottable}
+   * @constructs Plottable
+   *
+   **/
+  function Plottable(name, metadata, coordinates, idx, ci) {
+    /**
+     * Sample name.
+     * @type {string}
+     */
+    this.name = name;
+    /**
+     * Metadata values for the sample.
+     * @type {string[]}
+     */
+    this.metadata = metadata;
+    /**
+     * Position of the sample in the N-dimensional space.
+     * @type {float[]}
+     */
+    this.coordinates = coordinates;
+
+    /**
+     * The index of the sample in the array of meshes.
+     * @type {integer}
+     */
+    this.idx = idx === undefined ? -1 : idx;
+    /**
+     * Confidence intervals.
+     * @type {float[]}
+     */
+    this.ci = ci === undefined ? [] : ci;
+
+    if (this.ci.length !== 0) {
+      if (this.ci.length !== this.coordinates.length) {
+        throw new Error("The number of confidence intervals doesn't match " +
+                        'with the number of dimensions in the coordinates ' +
+                        'attribute. coords: ' + this.coordinates.length +
+                        ' ci: ' + this.ci.length);
+      }
+    }
+  };
+
+  /**
+   *
+   * Helper method to convert a Plottable into a string.
+   *
+   * @return {string} A string describing the Plottable object.
+   *
+   */
+  Plottable.prototype.toString = function() {
+    var ret = 'Sample: ' + this.name + ' located at: (' +
+              this.coordinates.join(', ') + ') metadata: [' +
+              this.metadata.join(', ') + ']';
+
+    if (this.idx === -1) {
+      ret = ret + ' without index';
+    }
+    else {
+      ret = ret + ' at index: ' + this.idx;
+    }
+
+    if (this.ci.length === 0) {
+      ret = ret + ' and without confidence intervals.';
+    }
+    else {
+      ret = ret + ' and with confidence intervals at (' + this.ci.join(', ') +
+        ').';
+    }
+
+    return ret;
+  };
+
+  /**
+   * @class DecompositionModel
+   *
+   * Models all the ordination data to be plotted.
+   *
+   * @param {string} name A string containing the abbreviated name of the
+   * ordination method.
+   * @param {string[]} ids An array of strings where each string is a sample
+   * identifier
+   * @param {float[]} coords A 2D Array of floats where each row contains the
+   * coordinates of a sample. The rows are in ids order.
+   * @param {float[]} pct_var An Array of floats where each position contains
+   * the percentage explained by that axis
+   * @param {float[]} md_headers An Array of string where each string is a
+   * metadata column header
+   * @param {string[]} metadata A 2D Array of strings where each row contains
+   * the metadata values for a given sample. The rows are in ids order. The
+   * columns are in `md_headers` order.
+   *
+   * @throws {Error} In any of the following cases:
+   * - The number of coordinates does not match the number of samples.
+   * - If there's a coordinate in `coords` that doesn't have the same length as
+   *   the rest.
+   * - The number of samples is different than the rows provided as metadata.
+   * - Not all metadata rows have the same number of fields.
+   *
+   * @return {DecompositionModel}
+   * @constructs DecompositionModel
+   *
+   */
+  function DecompositionModel(name, ids, coords, pct_var, md_headers,
+                              metadata, axesNames) {
+    var num_coords;
+    /**
+     * Abbreviated name of the ordination method used to create the data.
+     * @type {string}
+     */
+    this.abbreviatedName = name;
+    /**
+     * List of sample name identifiers.
+     * @type {string[]}
+     */
+    this.ids = ids;
+    /**
+     * Percentage explained by each of the axes in the ordination.
+     * @type {float[]}
+     */
+    this.percExpl = pct_var;
+    /**
+     * Column names for the metadata in the samples.
+     * @type {string[]}
+     */
+    this.md_headers = md_headers;
+    /**
+     * Names of the axes in the ordination
+     * @type {string[]}
+     */
+    this.axesNames = axesNames === undefined ? [] : axesNames;
+
+    /*
+      Check that the number of coordinates set provided are the same as the
+      number of samples
+    */
+    if (this.ids.length !== coords.length) {
+      throw new Error('The number of coordinates differs from the number of ' +
+                      'samples. Coords: ' + coords.length + ' samples: ' +
+                      this.ids.length);
+    }
+
+    /*
+      Check that all the coords set have the same number of coordinates
+    */
+    num_coords = coords[0].length;
+    var res = _.find(coords, function(c) {return c.length !== num_coords;});
+    if (res !== undefined) {
+      throw new Error('Not all samples have the same number of coordinates');
+    }
+
+    /*
+      Check that we have the percentage explained values for all coordinates
+    */
+    if (pct_var.length !== num_coords) {
+      throw new Error('The number of percentage explained values does not ' +
+                      'match the number of coordinates. Perc expl: ' +
+                      pct_var.length + ' Num coord: ' + num_coords);
+    }
+
+    /*
+      Check that we have the metadata for all samples
+    */
+    if (this.ids.length !== metadata.length) {
+      throw new Error('The number of metadata rows and the the number of ' +
+                      'samples do not match. Samples: ' + this.ids.length +
+                      ' Metadata rows: ' + metadata.length);
+    }
+
+    /*
+      Check that we have all the metadata categories in all rows
+    */
+    res = _.find(metadata, function(m) {
+                  return m.length !== md_headers.length;
+    });
+    if (res !== undefined) {
+      throw new Error('Not all metadata rows have the same number of values');
+    }
+
+    this.plottable = new Array(ids.length);
+    for (var i = 0; i < ids.length; i++) {
+      this.plottable[i] = new Plottable(ids[i], metadata[i], coords[i], i);
+    }
+
+    // use slice to make a copy of the array so we can modify it
+    /**
+     * Minimum and maximum values for each axis in the ordination. More
+     * concretely this object has a `min` and a `max` attributes, each with a
+     * list of floating point arrays that describe the minimum and maximum for
+     * each axis.
+     * @type {Object}
+     */
+    this.dimensionRanges = {'min': coords[0].slice(),
+                            'max': coords[0].slice()};
+    this.dimensionRanges = _.reduce(this.plottable,
+                                    DecompositionModel._minMaxReduce,
+                                    this.dimensionRanges);
+
+    this.length = this.plottable.length;
+    // TODO:
+    // this.edges = [];
+    // this.plotEdge = false;
+    // this.serialComparison = false;
+  }
+
+  /**
+   *
+   * Retrieve the plottable object with the given id.
+   *
+   * @param {string} id A string with the plottable.
+   *
+   * @return {Plottable} The plottable object for the given id.
+   *
+   */
+  DecompositionModel.prototype.getPlottableByID = function(id) {
+    idx = this.ids.indexOf(id);
+    if (idx === -1) {
+      throw new Error(id + ' is not found in the Decomposition Model ids');
+    }
+    return this.plottable[idx];
+  };
+
+  /**
+   *
+   * Retrieve all the plottable objects with the given ids.
+   *
+   * @param {integer[]} idArray an Array of strings where each string is a
+   * plottable id.
+   *
+   * @return {Plottable[]} An Array of plottable objects for the given ids.
+   *
+   */
+  DecompositionModel.prototype.getPlottableByIDs = function(idArray) {
+    dm = this;
+    return _.map(idArray, function(id) {return dm.getPlottableByID(id);});
+  };
+
+  /**
+   *
+   * Helper function that returns the index of a given metadata category.
+   *
+   * @param {string} category A string with the metadata header.
+   *
+   * @return {integer} An integer representing the index of the metadata
+   * category in the `md_headers` array.
+   *
+   */
+  DecompositionModel.prototype._getMetadataIndex = function(category) {
+    var md_idx = this.md_headers.indexOf(category);
+    if (md_idx === -1) {
+      throw new Error('The header ' + category +
+                      ' is not found in the metadata categories');
+    }
+    return md_idx;
+  };
+
+  /**
+   *
+   * Retrieve all the plottable objects under the metadata header value.
+   *
+   * @param {string} category A string with the metadata header.
+   * @param {string} value A string with the value under the metadata category.
+   *
+   * @return {Plottable[]} An Array of plottable objects for the given category
+   * value pair.
+   *
+   */
+  DecompositionModel.prototype.getPlottablesByMetadataCategoryValue = function(
+      category, value) {
+
+    var md_idx = this._getMetadataIndex(category);
+    var res = _.filter(this.plottable, function(pl) {
+      return pl.metadata[md_idx] === value; });
+
+    if (res.length === 0) {
+      throw new Error('The value ' + value +
+                      ' is not found in the metadata category ' + category);
+    }
+    return res;
+  };
+
+  /**
+   *
+   * Retrieve the available values for a given metadata category
+   *
+   * @param {string} category A string with the metadata header.
+   *
+   * @return {string[]} An array of the available values for the given metadata
+   * header.
+   *
+   */
+  DecompositionModel.prototype.getUniqueValuesByCategory = function(category) {
+    var md_idx = this._getMetadataIndex(category);
+    return _.uniq(
+      _.map(this.plottable, function(pl) {return pl.metadata[md_idx];}));
+  };
+
+  /**
+   *
+   * Executes the provided `func` passing all the plottables as parameters.
+   *
+   * @param {function} func The function to call for each plottable. It should
+   * accept a single parameter which will be the plottable.
+   *
+   * @return {Object[]} An array with the results of executing func over all
+   * plottables.
+   *
+   */
+  DecompositionModel.prototype.apply = function(func) {
+    return _.map(this.plottable, func);
+  };
+
+  /**
+   *
+   * Helper function used to find the minimum and maximum values every
+   * dimension in the plottable objects. This function is used with
+   * underscore.js' reduce function (_.reduce).
+   *
+   * @param {Object} accumulator An object with a "min" and "max" arrays that
+   * store the minimum and maximum values over all the plottables.
+   * @param {Plottable} plottable A plottable object to compare with.
+   *
+   * @return {Object} An updated version of accumulator, integrating the ranges
+   * of the newly seen plottable object.
+   * @private
+   *
+   **/
+  DecompositionModel._minMaxReduce = function(accumulator, plottable) {
+
+    // iterate over every dimension
+    _.each(plottable.coordinates, function(value, index) {
+      if (value > accumulator.max[index]) {
+        accumulator.max[index] = value;
+      }
+      else if (value < accumulator.min[index]) {
+        accumulator.min[index] = value;
+      }
+    });
+
+    return accumulator;
+  };
+
+  /**
+   *
+   * Helper method to convert a DecompositionModel into a string.
+   *
+   * @return {string} String representation describing the Decomposition
+   * object.
+   *
+   */
+  DecompositionModel.prototype.toString = function() {
+    return 'name: ' + this.abbreviatedName + '\n' +
+      'Metadata headers: [' + this.md_headers.join(', ') + ']\n' +
+      'Plottables:\n' + _.map(this.plottable, function(plt) {
+        return plt.toString();
+      }).join('\n');
+  };
+
+  return { 'DecompositionModel': DecompositionModel,
+           'Plottable': Plottable};
+});
diff --git a/emperor/support_files/js/scale-editor.js b/emperor/support_files/js/scale-editor.js
new file mode 100644
index 0000000..3552905
--- /dev/null
+++ b/emperor/support_files/js/scale-editor.js
@@ -0,0 +1,124 @@
+/**
+ * SlickGrid shape editor and formatter.
+ *
+ * @module SlickGridScale
+ */
+define([
+    'jquery',
+    'underscore',
+    'view',
+    'viewcontroller'
+],
+function($, _, DecompositionView, ViewControllers) {
+  /**
+   *
+   * @class Scale
+   *
+   * This class represents a range editor defined by the SlickGrid
+   * project.
+   * Note, this object is heavily based on classes in slick.editors.js and in
+   * the documentation that can be found [here]{@link
+   * https://github.com/mleibman/SlickGrid/wiki/Writing-custom-cell-editors}.
+   *
+   * @param {Object} args Arguments passed by SlickGrid.
+   * @alias module:SlickGridScale.ScaleEditor
+   */
+  function ScaleEditor(args) {
+    /**
+     * Node containing the jQuery slider
+     * @type {Node}
+     */
+    var $input;
+    /**
+     * Node containing the parent div holding the slider info
+     * @type {Node}
+     */
+    var $parentDiv;
+    /**
+     * Node containing the textbox for showing the slider value
+     * @type {Node}
+     */
+    var $viewval;
+    /**
+     * Initial value of the cell being edited.
+     * @type {Float}
+     */
+    var defaultValue;
+    var scope = this;
+
+    /* @constructor */
+    this.init = function() {
+      var pos = args.grid.getActiveCell();
+      var metaColPos = args.grid.getCellNodeBox(pos.row, pos.cell + 1);
+      var barLength = metaColPos.right - metaColPos.left - 10;
+      $parentDiv = $('<div style="flat:left;position:absolute;height:30px;' +
+                     'width:' + barLength + 'px;z-index:1000">');
+      $viewval = $('<input type="text" value="' + args.item.value +
+                   '" readonly  style="border:0;width:25px;">');
+      var $sliderDiv = $('<div style="width:' + barLength +
+                         'px;display:inline-block;' +
+                         'background-color:rgb(238, 238, 238)">');
+      $input = $sliderDiv.slider({
+        range: 'max',
+        min: 0.1,
+        max: 5.0,
+        value: args.item.value,
+        step: 0.1,
+        slide: function(event, ui) {
+          $viewval.val(ui.value);
+          args.item.value = ui.value;
+        },
+        stop: function(event, ui) {
+          // commit the changes as soon as a new scale is selected
+          // http://stackoverflow.com/a/15513516/379593
+          Slick.GlobalEditorLock.commitCurrentEdit();
+        }
+      });
+      $sliderDiv.appendTo($parentDiv);
+      $viewval.appendTo(args.container);
+
+      // Calculate the position for the parent div and add it to the view
+      var container = $(args.container);
+      $parentDiv.css('top', '5px');
+      $parentDiv.css('left', container.width() + 5);
+      $parentDiv.appendTo(args.container);
+    };
+
+    this.destroy = function() {
+      $parentDiv.remove();
+    };
+
+    this.focus = function() {
+      $input.focus();
+    };
+
+    this.focusout = function() {
+      $input.focusout();
+    };
+
+    this.isValueChanged = function() {
+      return $viewval.val() !== defaultValue;
+    };
+
+    this.serializeValue = function() {
+      return $viewval.val();
+    };
+
+    this.loadValue = function(item) {
+      defaultValue = item[args.column.field];
+      $input.val(defaultValue);
+    };
+
+    this.applyValue = function(item, state) {
+      item[args.column.field] = state;
+    };
+
+    this.validate = function() {
+      return {valid: true, msg: null};
+    };
+
+    this.init();
+  }
+
+  return {'ScaleEditor': ScaleEditor};
+});
diff --git a/emperor/support_files/js/scale-view-controller.js b/emperor/support_files/js/scale-view-controller.js
new file mode 100644
index 0000000..f5dcc58
--- /dev/null
+++ b/emperor/support_files/js/scale-view-controller.js
@@ -0,0 +1,278 @@
+define([
+    'jquery',
+    'underscore',
+    'util',
+    'viewcontroller',
+    'scale-editor'
+], function($, _, util, ViewControllers, ScaleEditor) {
+
+  // we only use the base attribute class, no need to get the base class
+  var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
+
+  /**
+   * @class ScaleViewController
+   *
+   * Alters the scale of points displayed on the screen.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {Object} decompViewDict This object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {ScaleViewController}
+   * @constructs ScaleViewController
+   * @extends EmperorAttributeABC
+   *
+   **/
+  function ScaleViewController(container, decompViewDict) {
+    var helpmenu = 'Change the scale of the attributes on the plot, allowing ' +
+                   'highlighting of points using size.';
+    var title = 'Scale';
+    // Create checkbox for scaling by values
+    /**
+     * jQuery node for checkbox controlling whether to scale by values or not
+     * @type {Node}
+     */
+    this.$scaledValue = $('<input type="checkbox">');
+    /**
+     * jQuery node for label of $scaledValues
+     * @type {Node}
+     */
+    this.$scaledLabel = $('<label>Scale by values</label>');
+
+    //Create global scale bar
+    /**
+     * jQuery node for global scale bar container div
+     * @type {Node}
+     */
+    this.$globalDiv = $('<div style="width:100%;padding:5px;">');
+    this.$globalDiv.html('<p>Global Scaling</p>');
+    var $sliderDiv = $('<div style="width:80%;display:inline-block;">');
+    var $viewval = $('<input type="text" value="1.0" readonly ' +
+                     'style="border:0;width:25px;' +
+                     'background-color:rgb(238, 238, 238)">');
+    /**
+     * jQuery node for global scale bar
+     * @type {Node}
+     */
+    this.$sliderGlobal = $sliderDiv.slider({
+        range: 'max',
+        min: 0.1,
+        max: 5.0,
+        value: 1.0,
+        step: 0.1,
+        slide: function(event, ui) {
+          $viewval.val(ui.value);
+        },
+        stop: function(event, ui) {
+          // Update the slickgrid values with the new scale
+          var data = scope.getSlickGridDataset();
+          _.each(data, function(element) {
+            element.value = ui.value;
+          });
+          scope.setSlickGridDataset(data);
+
+          //Update the scales for all meshes
+          var dv = scope.decompViewDict[scope.getActiveDecompViewKey()];
+          _.each(dv.markers, function(element) {
+            element.scale.set(ui.value, ui.value, ui.value);
+          });
+          dv.needsUpdate = true;
+        }
+      });
+    this.$globalDiv.append($viewval);
+    this.$globalDiv.append($sliderDiv);
+
+    // Constant for width in slick-grid
+    var SLICK_WIDTH = 50, scope = this;
+
+    // Build the options dictionary
+    var options = {'valueUpdatedCallback': function(e, args) {
+      var scale = +args.item.value;
+      var group = args.item.plottables;
+      var element = scope.decompViewDict[scope.getActiveDecompViewKey()];
+      scope.setPlottableAttributes(element, scale, group);
+    },
+      'categorySelectionCallback': function(evt, params) {
+        var category = scope.$select.val();
+
+        var k = scope.getActiveDecompViewKey();
+        var decompViewDict = scope.decompViewDict[k];
+
+        // getting all unique values per categories
+        var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
+          category);
+        // getting scale value for each point
+        var scaled = scope.$scaledValue.is(':checked');
+        try {
+          var attributes = scope.getScale(uniqueVals, scaled);
+        } catch (err) {
+          // Do not fire off action, instead just reshow globalDiv so we don't
+          // lose the current scaling values.
+          scope.$scaledValue.prop('checked', false);
+          return;
+        }
+        if (scaled) {
+          scope.$globalDiv.hide();
+        }
+        else {
+          scope.$globalDiv.show();
+        }
+        scope.resize();
+
+        // fetch the slickgrid-formatted data
+        var data = decompViewDict.setCategory(
+          attributes, scope.setPlottableAttributes, category);
+
+        scope.setSlickGridDataset(data);
+      },
+      'slickGridColumn': {id: 'title', name: '', field: 'value',
+        sortable: false, maxWidth: SLICK_WIDTH,
+        minWidth: SLICK_WIDTH,
+        autoEdit: true,
+        editor: ScaleEditor.ScaleEditor}};
+
+    EmperorAttributeABC.call(this, container, title, helpmenu,
+        decompViewDict, options);
+    this.$header.append(this.$scaledValue);
+    this.$header.append(this.$scaledLabel);
+    this.$body.prepend(this.$globalDiv);
+
+    scope.$scaledValue.on('change', options.categorySelectionCallback);
+
+    return this;
+  }
+  ScaleViewController.prototype = Object.create(EmperorAttributeABC.prototype);
+  ScaleViewController.prototype.constructor = EmperorAttributeABC;
+
+  /**
+   * Converts the current instance into a JSON string.
+   *
+   * @return {Object} JSON ready representation of self.
+   */
+  ScaleViewController.prototype.toJSON = function() {
+    var json = EmperorAttributeABC.prototype.toJSON.call(this);
+    json.globalScale = this.$globalDiv.children('input').val();
+    json.scaleVal = this.$scaledValue.is(':checked');
+    return json;
+  };
+
+  /**
+   * Decodes JSON string and modifies its own instance variables accordingly.
+   *
+   * @param {Object} Parsed JSON string representation of self.
+   */
+  ScaleViewController.prototype.fromJSON = function(json) {
+    // Can't call super because select needs to be set first
+    // Order here is important. We want to set all the extra controller
+    // settings before we load from json, as they can override the JSON when set
+    this.$select.val(json.category);
+    this.$select.trigger('chosen:updated');
+    this.$sliderGlobal.slider('value', json.globalScale);
+    this.$scaledValue.prop('checked', json.scaleVal);
+    this.$scaledValue.trigger('change');
+
+    // fetch and set the SlickGrid-formatted data
+    var k = this.getActiveDecompViewKey();
+    var data = this.decompViewDict[k].setCategory(
+      json.data, this.setPlottableAttributes, json.category);
+    this.setSlickGridDataset(data);
+    // set all to needsUpdate
+    this.decompViewDict[k].needsUpdate = true;
+  };
+
+  /**
+   * Resizes the container and the individual elements.
+   *
+   * Note, the consumer of this class, likely the main controller should call
+   * the resize function any time a resizing event happens.
+   *
+   * @param {float} width the container width.
+   * @param {float} height the container height.
+   */
+  ScaleViewController.prototype.resize = function(width, height) {
+    this.$body.height(this.$canvas.height() - this.$header.height());
+    this.$body.width(this.$canvas.width());
+
+    //scale gridDiv based on whether global scaling available or not
+    if (this.$scaledValue.is(':checked')) {
+      this.$gridDiv.css('height', '100%');
+    }
+    else {
+      this.$gridDiv.css(
+        'height', this.$body.height() - this.$globalDiv.height() - 10);
+    }
+
+    // call super, most of the header and body resizing logic is done there
+    EmperorAttributeABC.prototype.resize.call(this, width, height);
+  };
+
+  /**
+   * Helper function to set the scale of plottable
+   *
+   * @param {Object} scope The scope where the plottables exist
+   * @param {Boolean} scale New scaling factor of the plottables
+   * (1.0 being standard scale)
+   * @param {Object[]} group list of mesh objects that should be changed
+   * in scope
+   *
+   */
+  ScaleViewController.prototype.setPlottableAttributes = function(
+      scope, scale, group) {
+    var idx;
+
+    _.each(group, function(element) {
+      idx = element.idx;
+      scope.markers[idx].scale.set(scale, scale, scale);
+    });
+    scope.needsUpdate = true;
+  };
+
+  /**
+   * Helper function to get the scale for each metadata value
+   *
+   * @param {String[]} values The values to get scale for
+   * @param {Boolean} scaled Whether or not to scale by values or just reset to
+   * standard scale (1.0)
+   *
+   * @throws {Error} No or one numeric value in category and trying to scale by
+   * value
+   */
+  ScaleViewController.prototype.getScale = function(values, scaled) {
+    var scale = {};
+    if (!scaled) {
+      _.each(values, function(element) {
+        scale[element] = 1.0;
+      });
+    } else {
+      //See if we have numeric values, fail if no
+      var split = util.splitNumericValues(values);
+      if (split.numeric.length < 2) {
+        alert('Not enough numeric values in category, can not scale by value!');
+        throw new Error('no numeric values');
+      }
+
+      // Alert if we have non-numerics and scale them to 0
+      if (split.nonNumeric.length > 0) {
+        _.each(split.nonNumeric, function(element) {
+          scale[element] = 0.0;
+        });
+        alert('Non-numeric values detected. These will be hidden!');
+      }
+
+      //scale remaining values between 1 and 5 scale
+      var min = _.min(split.numeric);
+      var max = _.max(split.numeric);
+      var range = max - min;
+      _.each(split.numeric, function(element) {
+          // Scale the values, then round to 4 decimaal places.
+          scale[element] = Math.round(
+            (1 + (element - min) * 4 / range) * 10000) / 10000;
+        });
+    }
+    return scale;
+  };
+
+  return ScaleViewController;
+});
diff --git a/emperor/support_files/js/sceneplotview3d.js b/emperor/support_files/js/sceneplotview3d.js
new file mode 100644
index 0000000..c371185
--- /dev/null
+++ b/emperor/support_files/js/sceneplotview3d.js
@@ -0,0 +1,659 @@
+define([
+    'three',
+    'orbitcontrols',
+    'draw'
+], function(THREE, OrbitControls, draw) {
+  /** @private */
+  var makeLine = draw.makeLine;
+  /** @private */
+  var makeLabel = draw.makeLabel;
+
+  /**
+   *
+   * @class ScenePlotView3D
+   *
+   * Represents a three dimensional scene in THREE.js.
+   *
+   * @param {THREE.renderer} renderer THREE renderer object.
+   * @param {Object} decViews dictionary of DecompositionViews shown in this
+   * scene
+   * @param {Node} container Div where the scene will be rendered.
+   * @param {Float} xView Horizontal position of the rendered scene in the
+   * container element.
+   * @param {Float} yView Vertical position of the rendered scene in the
+   * container element.
+   * @param {Float} width The width of the renderer
+   * @param {Float} height The height of the renderer
+   *
+   * @return {ScenePlotView3D} An instance of ScenePlotView3D.
+   * @constructs ScenePlotView3D
+   */
+   function ScenePlotView3D(renderer, decViews, container, xView, yView,
+                            width, height) {
+    var scope = this;
+
+    // convert to jquery object for consistency with the rest of the objects
+    var $container = $(container);
+    this.decViews = decViews;
+    this.renderer = renderer;
+    /**
+     * Horizontal position of the scene.
+     * @type {Float}
+     */
+    this.xView = xView;
+    /**
+     * Vertical position of the scene.
+     * @type {Float}
+     */
+    this.yView = yView;
+    /**
+     * Width of the scene.
+     * @type {Float}
+     */
+    this.width = width;
+    /**
+     * Height of the scene.
+     * @type {Float}
+     */
+    this.height = height;
+    /**
+     * Axes color.
+     * @type {integer}
+     * @default 0xFFFFFF (white)
+     */
+    this.axesColor = 0xFFFFFF;
+    /**
+     * Background color.
+     * @type {integer}
+     * @default 0x000000 (black)
+     */
+    this.backgroundColor = 0x000000;
+
+    // used to name the axis lines/labels in the scene
+    this._axisPrefix = 'emperor-axis-line-';
+    this._axisLabelPrefix = 'emperor-axis-label-';
+
+    // Set up the camera
+    var max = _.max(decViews.scatter.decomp.dimensionRanges.max);
+    var frontFrust = _.min([max * 0.001, 1]);
+    var backFrust = _.max([max * 100, 100]);
+    /**
+     * Camera used to display the scene.
+     * @type {THREE.PerspectiveCamera}
+     */
+    this.camera = new THREE.PerspectiveCamera(35, width / height,
+                                              frontFrust, backFrust);
+    this.camera.position.set(0, 0, max * 5);
+
+    //need to initialize the scene
+    this.scene = new THREE.Scene();
+    this.scene.add(this.camera);
+    /**
+     * Object used to light the scene, by default is set to a light and
+     * transparent color (0x99999999).
+     * @type {THREE.DirectionalLight}
+     */
+    this.light = new THREE.DirectionalLight(0x999999, 2);
+    this.light.position.set(1, 1, 1).normalize();
+    this.camera.add(this.light);
+
+    // Add all the meshes to the scene, iterate through all keys in
+    // decomposition view dictionary
+    for (var decViewName in this.decViews) {
+      for (var j = 0; j < this.decViews[decViewName].markers.length; j++) {
+        this.scene.add(this.decViews[decViewName].markers[j]);
+      }
+    }
+
+    // use get(0) to retrieve the native DOM object
+    /**
+     * Object used to interact with the scene. By default it uses the mouse.
+     * @type {THREE.OrbitControls}
+     */
+    this.control = new THREE.OrbitControls(this.camera,
+                                           $container.get(0));
+    this.control.enableKeys = false;
+    this.control.rotateSpeed = 1.0;
+    this.control.zoomSpeed = 1.2;
+    this.control.panSpeed = 0.8;
+    this.control.enableZoom = true;
+    this.control.enablePan = true;
+    this.control.enableDamping = true;
+    this.control.dampingFactor = 0.3;
+    this.control.addEventListener('change', function() {
+      scope.needsUpdate = true;
+    });
+    this.control.update();
+    /**
+     * True when changes have occured that require re-rendering of the canvas
+     * @type {Boolean}
+     */
+    this.needsUpdate = true;
+    /**
+     * Array of integers indicating the index of the visible dimension at each
+     * axis ([x, y, z]).
+     * @type {Integer[]}
+     */
+    this.visibleDimensions = [0, 1, 2];
+    /**
+     * Object with "min" and "max" attributes each of which is an array with
+     * the ranges that covers all of the decomposition views.
+     * @type {Object}
+     */
+    this.dimensionRanges = {'max': [], 'min': []};
+    this.drawAxesWithColor(0xFFFFFF);
+    this.drawAxesLabelsWithColor(0xFFFFFF);
+
+    this._raycaster = new THREE.Raycaster();
+    this._mouse = new THREE.Vector2();
+
+    // initialize subscribers for event callbacks
+    /**
+     * Events allowed for callbacks. DO NOT EDIT.
+     * @type {String[]}
+     */
+    this.EVENTS = ['click', 'dblclick'];
+    /** @private */
+    this._subscribers = {};
+
+    for (var i = 0; i < this.EVENTS.length; i++) {
+      this._subscribers[this.EVENTS[i]] = [];
+    }
+
+    // Add callback call when sample is clicked
+    // Double and single click together from: http://stackoverflow.com/a/7845282
+    var DELAY = 200, clicks = 0, timer = null;
+    $container.on('click', function(event) {
+        clicks++;
+        if (clicks === 1) {
+            timer = setTimeout(function() {
+                scope._eventCallback('click', event);
+                clicks = 0;
+            }, DELAY);
+        }
+        else {
+            clearTimeout(timer);
+            scope._eventCallback('dblclick', event);
+            clicks = 0;
+        }
+    })
+    .on('dblclick', function(event) {
+        event.preventDefault();  //cancel system double-click event
+    });
+
+    //Add info div as bottom of canvas
+    this.$info = $('<div>');
+    this.$info.css('position', 'absolute')
+      .css('bottom', 0)
+      .css('height', 16)
+      .css('width', '50%')
+      .css('padding-left', 10)
+      .css('padding-right', 10)
+      .css('font-size', 12)
+      .css('z-index', 10000)
+      .css('background-color', 'rgb(238, 238, 238)')
+      .css('border', '1px solid black')
+      .css('font-family', 'Verdana,Arial,sans-serif')
+      .hide();
+    $(this.renderer.domElement).parent().append(this.$info);
+
+    // register callback for populating info with clicked sample name
+    // set the timeout for fading out the info div
+    var infoDuration = 2500;
+    var infoTimeout = setTimeout(function() {
+        scope.$info.fadeOut();
+      }, infoDuration);
+
+    this.on('click', function(n, i) {
+      clearTimeout(infoTimeout);
+      scope.$info.text(n);
+      scope.$info.show();
+
+      // reset the timeout for fading out the info div
+      infoTimeout = setTimeout(function() {
+        scope.$info.fadeOut();
+        scope.$info.text('');
+      }, infoDuration);
+    });
+  };
+
+  /**
+   *
+   * Utility method to find the union of the ranges in the decomposition views
+   * this method will populate the dimensionRanges attributes.
+   * @private
+   *
+   */
+  ScenePlotView3D.prototype._unionRanges = function() {
+    var scope = this, computeRanges;
+
+    // first check if there's any range data, if there isn't, then we need
+    // to compute it by looking at all the decompositions
+    computeRanges = scope.dimensionRanges.max.length === 0;
+
+    // if there's range data then check it lies within the global ranges
+    if (computeRanges === false) {
+      _.each(this.decViews, function(decView, name) {
+        var decomp = decView.decomp;
+
+        for (var i = 0; i < decomp.dimensionRanges.max.length; i++) {
+          // global
+          var gMax = scope.dimensionRanges.max[i];
+          var gMin = scope.dimensionRanges.min[i];
+
+          // local
+          var lMax = decomp.dimensionRanges.max[i];
+          var lMin = decomp.dimensionRanges.min[i];
+
+          // when we detect a point outside the global ranges we break and
+          // recompute them
+          if (!(gMin <= lMin && lMin <= gMax) ||
+              !(gMin <= lMax && lMax <= gMax)) {
+            computeRanges = true;
+            break;
+          }
+        }
+      });
+    }
+
+    if (computeRanges === false) {
+      // If at this point we still don't need to compute the data, it is safe
+      // to exit because all data still exists within the expected ranges
+      return;
+    }
+    else {
+      // TODO: If this entire function ever becomes a bottleneck we should only
+      // update the dimensions that changed.
+      // See: https://github.com/biocore/emperor/issues/526
+
+      // if we have to compute the data, clean up the previously known ranges
+      this.dimensionRanges.max = [];
+      this.dimensionRanges.max.length = 0;
+      this.dimensionRanges.min = [];
+      this.dimensionRanges.min.length = 0;
+    }
+
+    _.each(this.decViews, function(decView, name) {
+      // get each decomposition object
+      var decomp = decView.decomp;
+
+      if (scope.dimensionRanges.max.length === 0) {
+        scope.dimensionRanges.max = decomp.dimensionRanges.max.slice();
+        scope.dimensionRanges.min = decomp.dimensionRanges.min.slice();
+      }
+      else {
+        // when we have more than one decomposition view we need to figure out
+        // the absolute largest range that views span over
+        _.each(decomp.dimensionRanges.max, function(value, index) {
+          var vMax = decomp.dimensionRanges.max[index],
+              vMin = decomp.dimensionRanges.min[index];
+
+          if (vMax > scope.dimensionRanges.max[index]) {
+            scope.dimensionRanges.max[index] = vMax;
+          }
+          if (vMin < scope.dimensionRanges.min[index]) {
+            scope.dimensionRanges.min[index] = vMin;
+          }
+        });
+      }
+    });
+  };
+  /**
+   *
+   * Helper method used to iterate over the ranges of the visible dimensions.
+   *
+   * This function that centralizes the pattern followed by drawAxesWithColor
+   * and drawAxesLabelsWithColor.
+   *
+   * @param {Function} action a function that can take up to three arguments
+   * "start", "end" and "index".  And for each visible dimension the function
+   * will get the "start" and "end" of the range, and the current "index" of the
+   * visible dimension.
+   * @private
+   *
+   */
+  ScenePlotView3D.prototype._dimensionsIterator = function(action) {
+    this._unionRanges();
+
+    // shortcut to the index of the visible dimension and the range object
+    var x = this.visibleDimensions[0], y = this.visibleDimensions[1],
+        z = this.visibleDimensions[2], range = this.dimensionRanges;
+
+    // this is the "origin" of our ordination
+    var start = [range.min[x], range.min[y], range.min[z]];
+
+    var ends = [
+      [range.max[x], range.min[y], range.min[z]],
+      [range.min[x], range.max[y], range.min[z]],
+      [range.min[x], range.min[y], range.max[z]]
+    ];
+
+    action(start, ends[0], x);
+    action(start, ends[1], y);
+    action(start, ends[2], z);
+  };
+
+  /**
+   *
+   * Draw the axes lines in the plot
+   *
+   * @param {Integer} color An integer in hexadecimal that specifies the color
+   * of each of the axes lines, the length of these lines is determined by the
+   * dimensionRanges property.
+   *
+   */
+  ScenePlotView3D.prototype.drawAxesWithColor = function(color) {
+    var scope = this, axisLine;
+
+    this.removeAxes();
+
+    this._dimensionsIterator(function(start, end, index) {
+      axisLine = makeLine(start, end, color, 3, false);
+      axisLine.name = scope._axisPrefix + index;
+
+      scope.scene.add(axisLine);
+    });
+  };
+
+  /**
+   *
+   * Draw the axes labels for each visible dimension.
+   *
+   * The text in the labels is determined using the percentage explained by
+   * each dimension and the abbreviated name of a single decomposition object.
+   * Note that we arbitrarily use the first one, as all decomposition objects
+   * presented in the same scene should have the same percentages explained by
+   * each axis.
+   *
+   * @param {Integer} color An integer in hexadecimal that specifies the color
+   * of the labels, these labels will be positioned at the end of the axes line.
+   *
+   */
+  ScenePlotView3D.prototype.drawAxesLabelsWithColor = function(color) {
+    var scope = this, axisLabel, decomp, firstKey, text, factor;
+
+    factor = (this.dimensionRanges.max[0] - this.dimensionRanges.min[0]) * 0.9;
+
+    this.removeAxesLabels();
+
+    // get the first decomposition object, it doesn't really mater which one
+    // we look at though, as all of them should have the same percentage
+    // explained on each axis
+    firstKey = _.keys(this.decViews)[0];
+    decomp = this.decViews[firstKey].decomp;
+
+    this._dimensionsIterator(function(start, end, index) {
+
+      // construct a label of the format: AbbNam (xx.xx %)
+      if (decomp.abbreviatedName !== '') {
+        text = decomp.abbreviatedName;
+      }
+      else {
+        // when the labels get too long, it's a bit hard to look at
+        if (decomp.axesNames[index].length > 25) {
+          text = decomp.axesNames[index].slice(0, 20) + '...';
+        }
+        else {
+          text = decomp.axesNames[index];
+        }
+      }
+
+      // account for custom axes (their percentage explained will be -1 to
+      // indicate that this attribute is not meaningful).
+      if (decomp.percExpl[index] >= 0) {
+        text += ' (' + decomp.percExpl[index].toPrecision(4) + ' %)';
+      }
+
+      axisLabel = makeLabel(end, text, color, factor);
+      axisLabel.name = scope._axisLabelPrefix + index;
+
+      scope.scene.add(axisLabel);
+    });
+  };
+
+  /**
+   *
+   * Helper method to remove objects that match a prefix from the view's scene
+   * this method is used by removeAxes and removeAxesLabels. This function
+   * iterates "num" times, and for each iteration it finds and removes objects
+   * with the name of the form "prefix" + "iteration".
+   *
+   * @param {String} prefix The label that will prepended to the iterating
+   * index.
+   *
+   */
+  ScenePlotView3D.prototype._removeObjectsWithPrefix = function(prefix) {
+    var scope = this;
+    _.each(this.visibleDimensions, function(i) {
+      var axisLine = scope.scene.getObjectByName(prefix + i);
+      scope.scene.remove(axisLine);
+    });
+  };
+
+  /**
+   *
+   * Helper method to remove the axis lines from the scene
+   *
+   */
+  ScenePlotView3D.prototype.removeAxes = function() {
+    this._removeObjectsWithPrefix(this._axisPrefix);
+  };
+
+  /**
+   *
+   * Helper method to remove the axis labels from the scene
+   *
+   */
+  ScenePlotView3D.prototype.removeAxesLabels = function() {
+    this._removeObjectsWithPrefix(this._axisLabelPrefix);
+  };
+
+  /**
+   *
+   * Sets the aspect ratio of the camera according to the current size of the
+   * scene.
+   *
+   * @param {Float} winAspect ratio of width to height of the scene.
+   *
+   */
+  ScenePlotView3D.prototype.setCameraAspectRatio = function(winAspect) {
+    this.camera.aspect = winAspect;
+    this.camera.updateProjectionMatrix();
+  };
+
+  /**
+   *
+   * Resizes and relocates the scene.
+   *
+   * @param {Float} xView New horizontal location.
+   * @param {Float} yView New vertical location.
+   * @param {Float} width New scene width.
+   * @param {Float} height New scene height.
+   *
+   */
+  ScenePlotView3D.prototype.resize = function(xView, yView, width, height) {
+    this.xView = xView;
+    this.yView = yView;
+    this.width = width;
+    this.height = height;
+    this.setCameraAspectRatio(width / height);
+    this.needsUpdate = true;
+  };
+
+  /**
+   *
+   * Convenience method to check if this or any of the decViews under this need
+   * rendering
+   *
+   */
+   ScenePlotView3D.prototype.checkUpdate = function() {
+    var updateDimensions = false, updateColors = false,
+        currentDimensions, backgroundColor, axesColor;
+
+    // check if any of the decomposition views have changed
+    var updateData = _.any(this.decViews, function(dv) {
+      // note that we may be overwriting these variables, but we have a
+      // guarantee that if one of them changes for one of decomposition views,
+      // all of them will have changed, so grabbing one should be sufficient to
+      // perform the comparisons below
+      currentDimensions = dv.visibleDimensions;
+      backgroundColor = dv.backgroundColor;
+      axesColor = dv.axesColor;
+
+      return dv.needsUpdate;
+    });
+
+    // check if the visible dimensions have changed
+    if (!_.isEqual(currentDimensions, this.visibleDimensions)) {
+      // remove the current axes
+      this.removeAxes();
+      this.removeAxesLabels();
+
+      // get the new dimensions and re-display the data
+      this.visibleDimensions = _.clone(currentDimensions);
+      this.drawAxesWithColor(this.axesColor);
+      this.drawAxesLabelsWithColor(this.axesColor);
+
+      updateDimensions = true;
+    }
+
+    // check if we should change the axes color
+    if (axesColor !== this.axesColor) {
+      this.drawAxesWithColor(axesColor);
+      this.drawAxesLabelsWithColor(axesColor);
+
+      this.axesColor = _.clone(axesColor);
+
+      updateColors = true;
+    }
+
+    // check if we should change the background color
+    if (backgroundColor !== this.backgroundColor) {
+      this.renderer.setClearColor(new THREE.Color(backgroundColor));
+      this.backgroundColor = _.clone(backgroundColor);
+
+      updateColors = true;
+    }
+
+    // if autorotation is enabled, then update the controls to trigger an
+    // update, it's an equivalent to asking for re-rendering
+    if (this.control.autoRotate) {
+      this.control.update();
+    }
+
+    if (updateData) {
+      this.drawAxesWithColor(this.axesColor);
+      this.drawAxesLabelsWithColor(this.axesColor);
+    }
+
+    // if anything has changed, then trigger an update
+    return this.needsUpdate || updateData || updateDimensions || updateColors;
+   };
+
+  /**
+   *
+   * Convenience method to re-render the contents of the scene.
+   *
+   */
+  ScenePlotView3D.prototype.render = function() {
+    this.renderer.setViewport(this.xView, this.yView, this.width, this.height);
+    this.renderer.render(this.scene, this.camera);
+    var camera = this.camera;
+    //point all samples towards the camera
+    _.each(this.decViews.scatter.markers, function(element) {
+      element.quaternion.copy(camera.quaternion);
+    });
+    this.needsUpdate = false;
+    $.each(this.decViews, function(key, val) {
+      val.needsUpdate = false;
+    });
+  };
+
+  /**
+   *
+   * Helper method that runs functions subscribed to the container's callbacks.
+   * @param {String} eventType Event type being called
+   * @param {event} event The event from jQuery, with x and y click coords
+   * @private
+   *
+   */
+  ScenePlotView3D.prototype._eventCallback = function(eventType, event) {
+    event.preventDefault();
+    // don't do anything if no subscribers
+    if (this._subscribers[eventType].length === 0) {
+      return;
+    }
+
+    var element = this.renderer.domElement;
+    var offset = $(element).offset();
+    this._mouse.x = ((event.clientX - offset.left) / element.width) * 2 - 1;
+    this._mouse.y = -((event.clientY - offset.top) / element.height) * 2 + 1;
+
+    this._raycaster.setFromCamera(this._mouse, this.camera);
+
+    var intersects = this._raycaster.intersectObjects(
+      this.decViews.scatter.markers);
+
+    // Get first intersected item and call callback with it.
+    if (intersects.length > 0) {
+      var intersect = intersects[0].object;
+
+      for (var i = 0; i < this._subscribers[eventType].length; i++) {
+        // keep going if one of the callbacks fails
+        try {
+          this._subscribers[eventType][i](intersect.name, intersect);
+        } catch (e) {
+          console.error(e);
+        }
+        this.needsUpdate = true;
+      }
+    }
+  };
+
+  /**
+   *
+   * Interface to subscribe to event types in the canvas, see the EVENTS
+   * property.
+   *
+   * @param {String} eventType The type of event to subscribe to.
+   * @param {Function} handler Function to call when `eventType` is triggered,
+   * receives two parameters, a string with the name of the object, and the
+   * object itself i.e. f(objectName, object).
+   *
+   * @throws {Error} If the given eventType is unknown.
+   *
+   */
+  ScenePlotView3D.prototype.on = function(eventType, handler) {
+    if (this.EVENTS.indexOf(eventType) === -1) {
+      throw new Error('Unknown event ' + eventType + '. Known events are: ' +
+                      this.EVENTS.join(', '));
+    }
+
+    this._subscribers[eventType].push(handler);
+  };
+
+  /**
+   *
+   * Interface to unsubscribe a function from an event type, see the EVENTS
+   * property.
+   *
+   * @param {String} eventType The type of event to unsubscribe from.
+   * @param {Function} handler Function to remove from the subscribers list.
+   *
+   * @throws {Error} If the given eventType is unknown.
+   *
+   */
+  ScenePlotView3D.prototype.off = function(eventType, handler) {
+    if (this.EVENTS.indexOf(eventType) === -1) {
+      throw new Error('Unknown event ' + eventType + '. Known events are ' +
+                      this.EVENTS.join(', '));
+    }
+
+    var pos = this._subscribers[eventType].indexOf(handler);
+    if (pos !== -1) {
+      this._subscribers[eventType].splice(pos, 1);
+    }
+  };
+
+  return ScenePlotView3D;
+});
diff --git a/emperor/support_files/js/shape-controller.js b/emperor/support_files/js/shape-controller.js
new file mode 100644
index 0000000..5c829d5
--- /dev/null
+++ b/emperor/support_files/js/shape-controller.js
@@ -0,0 +1,108 @@
+define([
+    'jquery',
+    'underscore',
+    'viewcontroller',
+    'shape-editor',
+    'shapes'
+], function($, _, ViewControllers, Shape, shapes) {
+
+  // we only use the base attribute class, no need to get the base class
+  var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
+  var ShapeEditor = Shape.ShapeEditor;
+  var ShapeFormatter = Shape.ShapeFormatter;
+  /**
+   * @class ShapeController
+   *
+   * Manipulates and displays the shape of objects on screen.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {Object} decompViewDict This is object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {ShapeController} An instance of ShapeController
+   * @constructs ShapeController
+   * @extends EmperorAttributeABC
+   */
+  function ShapeController(container, decompViewDict) {
+    var helpmenu = 'Change the shapes representing groups of data on the plot';
+    var title = 'Shape';
+
+    // Constant for width in slick-grid
+    var SLICK_WIDTH = 100, scope = this;
+    var name, value, shapeItem;
+
+    // Build the options dictionary
+    var options = {
+      'valueUpdatedCallback': function(e, args) {
+        var val = args.item.category, shape = args.item.value;
+        var group = args.item.plottables;
+        var element = scope.decompViewDict[scope.getActiveDecompViewKey()];
+        scope.setPlottableAttributes(element, shape, group);
+      },
+      'categorySelectionCallback': function(evt, params) {
+        var category = scope.$select.val();
+
+        var k = scope.getActiveDecompViewKey();
+        var decompViewDict = scope.decompViewDict[k];
+
+        // getting all unique values per categories
+        var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
+          category);
+
+        // Reset all to shapes to default
+        var attributes = {};
+        for (var index in uniqueVals) {
+          attributes[uniqueVals[index]] = 'Sphere';
+        }
+        // fetch the slickgrid-formatted data
+        var data = decompViewDict.setCategory(
+          attributes, scope.setPlottableAttributes, category);
+
+        scope.setSlickGridDataset(data);
+      },
+      'slickGridColumn': {
+        id: 'title', name: '', field: 'value',
+        sortable: false, maxWidth: SLICK_WIDTH, minWidth: SLICK_WIDTH,
+        autoEdit: true,
+        editor: ShapeEditor,
+        formatter: ShapeFormatter
+      }
+    };
+
+    EmperorAttributeABC.call(this, container, title, helpmenu,
+                             decompViewDict, options);
+    return this;
+  }
+
+  ShapeController.prototype = Object.create(EmperorAttributeABC.prototype);
+  ShapeController.prototype.constructor = EmperorAttributeABC;
+
+  /**
+   * Helper function to set the shape of plottable
+   *
+   * @param {Object} scope The scope where the plottables exist
+   * @param {string} shape String representation of the shape to be applied
+   * to the plottables.
+   * @param {Object[]} group Array of objects that should be changed in scope
+   */
+  ShapeController.prototype.setPlottableAttributes =
+      function(scope, shape, group) {
+    var idx;
+
+    // get the appropriately sized geometry
+    var geometry = shapes.getGeometry(shape, scope.decomp.dimensionRanges);
+
+    if (geometry === undefined) {
+      throw new Error('Unknown shape ' + shape);
+    }
+
+    _.each(group, function(element) {
+      idx = element.idx;
+      scope.markers[idx].geometry = geometry;
+    });
+    scope.needsUpdate = true;
+  };
+  return ShapeController;
+});
diff --git a/emperor/support_files/js/shape-editor.js b/emperor/support_files/js/shape-editor.js
new file mode 100644
index 0000000..cdd6fea
--- /dev/null
+++ b/emperor/support_files/js/shape-editor.js
@@ -0,0 +1,106 @@
+/**
+ * SlickGrid shape editor and formatter.
+ *
+ * @module SlickGridShapes
+ */
+define([
+    'jquery',
+    'underscore',
+    'view',
+    'viewcontroller',
+    'shapes'
+],
+function($, _, DecompositionView, ViewControllers, shapes) {
+
+  /**
+   * @class ShapeEditor
+   *
+   * This class represents a dropdown editor defined by the SlickGrid project.
+   *
+   * Note, this object is heavily based on classes in slick.editors.js and in
+   * the documentation that can be found [here](https://github.com/mleibman/
+   * SlickGrid/wiki/Writing-custom-cell-editors)
+   *
+   * Also see ShapeFormatter, a function in charge of formatting a dropdown for
+   * the SlickGrid object.
+   *
+   * @param {Object} args Arguments passed by SlickGrid.
+   * @alias module:SlickGridShapes.ShapeEditor
+   */
+  function ShapeEditor(args) {
+    var $input;
+    var defaultValue;
+    var scope = this;
+
+    this.init = function() {
+      $input = shapes.$shapesDropdown;
+      $input.appendTo(args.container);
+      $input.on('change', function() {
+        // commit the changes as soon as a new shape is selected
+        // http://stackoverflow.com/a/15513516/379593
+        Slick.GlobalEditorLock.commitCurrentEdit();
+      });
+    };
+
+    this.destroy = function() {
+      $input.remove();
+    };
+
+    this.focus = function() {
+      $input.focus();
+    };
+
+    this.focusout = function() {
+      $input.focusout();
+    };
+
+    this.isValueChanged = function() {
+      return $input.val() !== defaultValue;
+    };
+
+    this.serializeValue = function() {
+      return $input.val();
+    };
+
+    this.loadValue = function(item) {
+      defaultValue = item[args.column.field];
+      $input.val(defaultValue);
+      $input[0].defaultValue = defaultValue;
+      $input.select();
+    };
+
+    this.applyValue = function(item, state) {
+      item[args.column.field] = state;
+    };
+
+    this.validate = function() {
+      return {valid: true, msg: null};
+    };
+
+    this.init();
+  }
+
+
+  /**
+   *
+   * Function to format shape dropdown for the SlickGrid object.
+   *
+   * This formatter is heavily based in the examples found in
+   * [slick.formattters.js](https://github.com/6pac/SlickGrid/blob/master/
+   * slick.formatters.js).
+   *
+   * @param {Object} row SlickGrid row.
+   * @param {Object} cell SlickGrid cell.
+   * @param {string} value the value in the row.
+   * @param {Objecy} columnDef SlickGrid column definition.
+   * @param {Object} dataContext data model of the SlickGrid object
+   *
+   * @return {string} The HTML of the div and value
+   * @function ShapeFormatter
+   */
+  function ShapeFormatter(row, cell, value, columnDef, dataContext) {
+    return '<div>' + value + '</div>';
+  }
+
+  return {'ShapeEditor': ShapeEditor, 'ShapeFormatter': ShapeFormatter};
+});
diff --git a/emperor/support_files/js/shapes.js b/emperor/support_files/js/shapes.js
new file mode 100644
index 0000000..3cac827
--- /dev/null
+++ b/emperor/support_files/js/shapes.js
@@ -0,0 +1,55 @@
+// Module to avoid duplication of shape sources between controller and
+// editor/formatter. This allows one central dict and dropdown of available
+// shapes.
+define(['jquery', 'three', 'underscore'], function($, THREE, _) {
+
+  var SPHERE = 'Sphere', CUBE = 'Cube', CONE = 'Cone',
+      ICOSAHEDRON = 'Icosahedron', CYLINDER = 'Cylinder';
+
+  var shapes = [SPHERE, CUBE, CONE, ICOSAHEDRON, CYLINDER];
+
+  /**
+   *
+   * Return a correctly sized geometry that matches the plotting space
+   *
+   * @param {string} shapeName One of 'Sphere', 'Cube', 'Cone', 'Icosahedron'
+   * or 'Cylinder'.
+   * @param {Object} ranges Object with two arrays of "max" and "min" values as
+   * generated by the `DecompositionModel` dimensionRanges property
+   *
+   * @return {THREE.Geometry} The requested geometry object with a size
+   * appropriate for the data presented on screen.
+   * @function getGeometry
+   */
+  function getGeometry(shapeName, ranges) {
+
+    // this is a heauristic tested on numerous plots since 2013, based off of
+    // the old implementation of emperor. We select the dimensions of all the
+    // geometries based on this factor.
+    var factor = (ranges.max[0] - ranges.min[0]) * 0.012;
+
+    switch (shapeName) {
+      case SPHERE:
+        return new THREE.SphereGeometry(factor, 8, 8);
+      case CUBE:
+        return new THREE.CubeGeometry(factor, factor, factor, 8, 8, 8);
+      case CONE:
+        return new THREE.CylinderGeometry(factor * 0.4, 0, 1.5 * factor, 8);
+      case ICOSAHEDRON:
+        return new THREE.IcosahedronGeometry(factor, 0);
+      case CYLINDER:
+        return new THREE.CylinderGeometry(factor * 0.4, factor * 0.4,
+                                          1.5 * factor, 10);
+      default:
+        throw Error('Unknown geometry requested: ' + shapeName);
+    }
+  }
+
+  var $shapesDropdown = $('<select>');
+  _.each(shapes, function(shape) {
+    $shapesDropdown.append(new Option(shape, shape));
+  });
+
+  return {$shapesDropdown: $shapesDropdown, getGeometry: getGeometry,
+          shapes: shapes};
+});
diff --git a/emperor/support_files/js/specifications.txt b/emperor/support_files/js/specifications.txt
deleted file mode 100644
index e499fd1..0000000
--- a/emperor/support_files/js/specifications.txt
+++ /dev/null
@@ -1 +0,0 @@
-Study names are passed as all lowercase with no spaces
\ No newline at end of file
diff --git a/emperor/support_files/js/spectrum.js b/emperor/support_files/js/spectrum.js
deleted file mode 100755
index 2680f80..0000000
--- a/emperor/support_files/js/spectrum.js
+++ /dev/null
@@ -1,1566 +0,0 @@
-// Spectrum: The No Hassle Colorpicker
-// https://github.com/bgrins/spectrum
-// Author: Brian Grinstead
-// License: MIT
-// Requires: jQuery, spectrum.css
-
-(function (window, $, undefined) {
-    var defaultOpts = {
-        
-        // Events
-        beforeShow: noop,
-        move: noop,
-        change: noop,
-        show: noop,
-        hide: noop,
-        
-        // Options
-        color: false,
-        flat: false,
-        showInput: false,
-        showButtons: true,
-        showInitial: false,
-        showPalette: false,
-        showPaletteOnly: false,
-        showSelectionPalette: true,
-        localStorageKey: false,
-        maxSelectionSize: 7,
-        cancelText: "cancel",
-        chooseText: "choose",
-        preferredFormat: false,
-        className: "",
-        theme: "sp-light",
-        palette: ['fff', '000'],
-        selectionPalette: []
-    },
-    spectrums = [],
-    IE = $.browser.msie,
-    replaceInput = [
-        "<div class='sp-replacer'>",
-            "<div class='sp-preview'></div>",
-            "<div class='sp-dd'>▼</div>",
-        "</div>"
-    ].join(''),
-    markup = (function () {
-
-        // IE does not support gradients with multiple stops, so we need to simulate            
-        //  that for the rainbow slider with 8 divs that each have a single gradient
-        var gradientFix = "";
-        if (IE) {
-            for (var i = 1; i <= 6; i++) {
-                gradientFix += "<div class='sp-" + i + "'></div>";
-            }
-        }
-
-        return [
-            "<div class='sp-container'>",
-                "<div class='sp-palette-container'>",
-                    "<div class='sp-palette sp-thumb sp-cf'></div>",
-                "</div>",
-                "<div class='sp-picker-container'>",
-                    "<div class='sp-top sp-cf'>",
-                        "<div class='sp-fill'></div>",
-                        "<div class='sp-top-inner'>",
-                            "<div class='sp-color'>",
-                                "<div class='sp-sat'>",
-                                    "<div class='sp-val'>",
-                                        "<div class='sp-dragger'></div>",
-                                    "</div>",
-                                "</div>",
-                            "</div>",
-                            "<div class='sp-hue'>",
-                                "<div class='sp-slider'></div>",
-                                gradientFix,
-                            "</div>",
-                        "</div>",
-                    "</div>",
-                    "<div class='sp-input-container sp-cf'>",
-                        "<input class='sp-input' type='text' spellcheck='false'  />",
-                    "</div>",
-                    "<div class='sp-initial sp-thumb sp-cf'></div>",
-                    "<div class='sp-button-container sp-cf'>",
-                        "<a class='sp-cancel' href='#'></a>",
-                        "<button class='sp-choose'></button>",
-                    "</div>",
-                "</div>",
-            "</div>"
-        ].join("");
-    })(),
-    paletteTemplate = function (p, color, className) {
-        var html = [];
-        for (var i = 0; i < p.length; i++) {
-            var tiny = tinycolor(p[i]);
-            var c = tiny.toHsl().l < .5 ? "sp-thumb-dark" : "sp-thumb-light";
-            c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : "";
-            html.push('<span title="' + tiny.toHexString() + '" data-color="' + tiny.toHexString() + '" style="background-color:' + tiny.toRgbString() + ';" class="' + c + '"></span>');
-        }
-        return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
-    };
-
-    function hideAll() {
-        for (var i = 0; i < spectrums.length; i++) {
-            if (spectrums[i]) {
-                spectrums[i].hide();
-            }
-        }
-    }
-    function instanceOptions(o, callbackContext) {
-        var opts = $.extend({}, defaultOpts, o);
-        opts.callbacks = {
-            'move': bind(opts.move, callbackContext),
-            'change': bind(opts.change, callbackContext),
-            'show': bind(opts.show, callbackContext),
-            'hide': bind(opts.hide, callbackContext),
-            'beforeShow': bind(opts.beforeShow, callbackContext)
-        };
-
-        return opts;
-    }
-
-    function spectrum(element, o) {
-
-        var opts = instanceOptions(o, element),
-            flat = opts.flat,
-            showPaletteOnly = opts.showPaletteOnly,
-            showPalette = opts.showPalette || showPaletteOnly,
-            showInitial = opts.showInitial && !flat,
-            showInput = opts.showInput,
-            showSelectionPalette = opts.showSelectionPalette,
-            localStorageKey = opts.localStorageKey,
-            theme = opts.theme,
-            callbacks = opts.callbacks,
-            resize = throttle(reflow, 10),
-            visible = false,
-            dragWidth = 0,
-            dragHeight = 0,
-            dragHelperHeight = 0,
-            slideHeight = 0,
-            slideWidth = 0,
-            slideHelperHeight = 0,
-            currentHue = 0,
-            currentSaturation = 0,
-            currentValue = 0,
-            palette = opts.palette.slice(0),
-            paletteArray = $.isArray(palette[0]) ? palette : [palette],
-            selectionPalette = opts.selectionPalette.slice(0),
-            draggingClass = "sp-dragging";
-
-        var doc = element.ownerDocument,
-            body = doc.body,
-            boundElement = $(element),
-            container = $(markup, doc).addClass(theme),
-            dragger = container.find(".sp-color"),
-            dragHelper = container.find(".sp-dragger"),
-            slider = container.find(".sp-hue"),
-            slideHelper = container.find(".sp-slider"),
-            textInput = container.find(".sp-input"),
-            paletteContainer = container.find(".sp-palette"),
-            initialColorContainer = container.find(".sp-initial"),
-            cancelButton = container.find(".sp-cancel"),
-            chooseButton = container.find(".sp-choose"),
-            isInput = boundElement.is("input"),
-            shouldReplace = isInput && !flat,
-            replacer = (shouldReplace) ? $(replaceInput).addClass(theme) : $([]),
-            offsetElement = (shouldReplace) ? replacer : boundElement,
-            previewElement = replacer.find(".sp-preview"),
-            initialColor = opts.color || (isInput && boundElement.val()),
-            colorOnShow = false,
-            preferredFormat = opts.preferredFormat,
-            currentPreferredFormat = preferredFormat,
-            clickoutFiresChange = !opts.showButtons;
-            
-        chooseButton.text(opts.chooseText);
-        cancelButton.text(opts.cancelText);
-
-        function initialize() {
-
-            if (IE) {
-                container.find("*:not(input)").attr("unselectable", "on");
-            }
-
-            container.toggleClass("sp-flat", flat);
-            container.toggleClass("sp-input-disabled", !showInput);
-            container.toggleClass("sp-buttons-disabled", !opts.showButtons || flat);
-            container.toggleClass("sp-palette-disabled", !showPalette);
-            container.toggleClass("sp-palette-only", showPaletteOnly);
-            container.toggleClass("sp-initial-disabled", !showInitial);
-            container.addClass(opts.className);
-
-            if (shouldReplace) {
-                boundElement.hide().after(replacer);
-            }
-
-            if (flat) {
-                boundElement.after(container).hide();
-            }
-            else {
-                $(body).append(container.hide());
-            }
-            if (localStorageKey && window.localStorage) {
-                try {
-                    selectionPalette = window.localStorage[localStorageKey].split(",");
-                }
-                catch (e) {
-
-                }
-            }
-
-            offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
-                toggle();
-
-                e.stopPropagation();
-
-                if (!$(e.target).is("input")) {
-                    e.preventDefault();
-                }
-            });
-
-            // Prevent clicks from bubbling up to document.  This would cause it to be hidden.
-            container.click(stopPropagation);
-
-            // Handle user typed input
-            textInput.change(setFromTextInput);
-            textInput.bind("paste", function () {
-                setTimeout(setFromTextInput, 1);
-            });
-            textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
-
-            cancelButton.bind("click.spectrum", function (e) {
-                e.stopPropagation();
-                e.preventDefault();
-
-                hide();
-            });
-
-            chooseButton.bind("click.spectrum", function (e) {
-                e.stopPropagation();
-                e.preventDefault();
-
-                if (isValid()) {
-                    updateOriginalInput();
-                    hide();
-                }
-            });
-
-            draggable(slider, function (dragX, dragY) {
-                currentHue = (dragY / slideHeight);
-                move();
-            }, dragStart, dragStop);
-
-            draggable(dragger, function (dragX, dragY) {
-                currentSaturation = dragX / dragWidth;
-                currentValue = (dragHeight - dragY) / dragHeight;
-                move();
-            }, dragStart, dragStop);
-            
-            if (!!initialColor) {
-                set(initialColor, true);
-                addColorToSelectionPalette(initialColor);
-            }
-            else {
-                updateUI();
-            }
-
-            if (flat) {
-                show();
-            }
-
-            function palletElementClick(e) {
-                if (e.data && e.data.ignore) {
-                    set($(this).data("color"), true);
-                    move();
-                }
-                else {
-                    set($(this).data("color"));
-                    move();
-                    hide();
-                }
-
-                return false;
-            }
-
-            var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
-            paletteContainer.delegate("span", paletteEvent, palletElementClick);
-            initialColorContainer.delegate("span::nth-child(1)", paletteEvent, { ignore: true }, palletElementClick);
-        }
-        function addColorToSelectionPalette(color) {
-            if (showSelectionPalette) {
-                selectionPalette.push(tinycolor(color).toHexString());
-                if (localStorageKey && window.localStorage) {
-                    window.localStorage[localStorageKey] = selectionPalette.join(",");
-                }
-            }
-        }
-
-        function getUniqueSelectionPalette() {
-            var unique = [];
-            var p = selectionPalette;
-            var paletteLookup = {};
-
-            if (showPalette) {
-
-                for (var i = 0; i < paletteArray.length; i++) {
-                    for (var j = 0; j < paletteArray[i].length; j++) {
-                        var hex = tinycolor(paletteArray[i][j]).toHexString();
-                        paletteLookup[hex] = true;
-                    }
-                }
-
-                for (var i = 0; i < p.length; i++) {
-                    var color = tinycolor(p[i]);
-                    var hex = color.toHexString();
-
-                    if (!paletteLookup.hasOwnProperty(hex)) {
-                        unique.push(p[i]);
-                        paletteLookup[hex] = true;
-                    }
-                }
-            }
-
-            return unique.reverse().slice(0, opts.maxSelectionSize);
-        }
-        function drawPalette() {
-
-            var currentColor = get();
-
-            var html = $.map(paletteArray, function (palette, i) {
-                return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i);
-            });
-
-            if (selectionPalette) {
-                html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection"));
-            }
-
-            paletteContainer.html(html.join(""));
-        }
-        function drawInitial() {
-            if (showInitial) {
-                var initial = colorOnShow;
-                var current = get();
-                initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial"));
-            }
-        }
-        function dragStart() {
-            if (dragHeight === 0 || dragWidth === 0 || slideHeight === 0) {
-                reflow();
-            }
-            container.addClass(draggingClass);
-        }
-        function dragStop() {
-            container.removeClass(draggingClass);
-        }
-        function setFromTextInput() {
-            var tiny = tinycolor(textInput.val());
-            if (tiny.ok) {
-                set(tiny, true);
-            }
-            else {
-                textInput.addClass("sp-validation-error");
-            }
-        }
-
-        function toggle() {
-            (visible) ? hide() : show();
-        }
-
-        function show() {
-            if (visible) { 
-                reflow();
-                return;
-            }
-            if (callbacks.beforeShow(get()) === false) return;
-
-            hideAll();
-            visible = true;
-
-            $(doc).bind("click.spectrum", hide);
-            $(window).bind("resize.spectrum", resize);
-            replacer.addClass("sp-active");
-            container.show();
-
-            if (showPalette) {
-                drawPalette();
-            }
-            reflow();
-            updateUI();
-            
-            colorOnShow = get();
-            
-            drawInitial();
-            callbacks.show(colorOnShow);
-        }
-
-        function hide() {
-            if (!visible || flat) { return; }
-            visible = false;
-
-            $(doc).unbind("click.spectrum", hide);
-            $(window).unbind("resize.spectrum", resize);
-
-            replacer.removeClass("sp-active");
-            container.hide();
-
-            var colorHasChanged = !tinycolor.equals(get(), colorOnShow);
-
-            if (colorHasChanged) {
-                if (clickoutFiresChange) {
-                    updateOriginalInput();
-                }
-                else {
-                    revert();
-                }
-            }
-
-            callbacks.hide(get());
-        }
-
-        function revert() {
-            set(colorOnShow, true, true);
-        }
-        
-        function set(color, ignoreChange, ignoreFormatChange) {
-            if (tinycolor.equals(color, get())) {
-                return;
-            }
-
-            var newColor = tinycolor(color);
-            var newHsv = newColor.toHsv();
-            
-            currentHue = newHsv.h;
-            currentSaturation = newHsv.s;
-            currentValue = newHsv.v;
-
-            updateUI();
-
-            if (!ignoreFormatChange) {
-                currentPreferredFormat = preferredFormat || newColor.format;
-            }
-            
-            // set can be called from a default value,  don't want to trigger a change in that case
-            if (!ignoreChange && !tinycolor.equals(color, colorOnShow)) {
-                updateOriginalInput();
-            }
-        }
-
-        function get() {
-            return tinycolor.fromRatio({ h: currentHue, s: currentSaturation, v: currentValue });
-        }
-
-        function isValid() {
-            return !textInput.hasClass("sp-validation-error");
-        }
-
-        function move() {
-            updateUI();
-            
-            callbacks.move(get());
-        }
-
-        function updateUI() {
-
-            textInput.removeClass("sp-validation-error");
-
-            updateHelperLocations();
-
-            // Update dragger background color (gradients take care of saturation and value).
-            var flatColor = tinycolor({ h: currentHue, s: "1.0", v: "1.0" });
-            dragger.css("background-color", flatColor.toHexString());
-
-            var realColor = get(),
-                realHex = realColor.toHexString();
-
-            // Update the replaced elements background color (with actual selected color)
-            previewElement.css("background-color", realHex);
-
-            // Update the text entry input as it changes happen
-            if (showInput) {
-                textInput.val(realColor.toString(currentPreferredFormat));
-            }
-
-            if (showPalette) {
-                drawPalette();
-            }
-
-            drawInitial();
-        }
-
-        function updateHelperLocations() {
-            var h = currentHue;
-            var s = currentSaturation;
-            var v = currentValue;
-
-            // Where to show the little circle in that displays your current selected color
-            var dragX = s * dragWidth;
-            var dragY = dragHeight - (v * dragHeight);
-            dragX = Math.max(
-                -dragHelperHeight,
-                Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
-            );
-            dragY = Math.max(
-                -dragHelperHeight,
-                Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
-            );
-            dragHelper.css({
-                "top": dragY,
-                "left": dragX
-            });
-
-            // Where to show the bar that displays your current selected hue
-            var slideY = (currentHue) * slideHeight;
-            slideHelper.css({
-                "top": slideY - slideHelperHeight
-            });
-        }
-
-        function updateOriginalInput() {
-            var color = get();
-            
-            if (isInput) {
-                boundElement.val(color.toString(currentPreferredFormat)).change();
-            }
-            
-            colorOnShow = color;
-
-            // Update the selection palette with the current color
-            addColorToSelectionPalette(color);
-                
-            callbacks.change(color);
-        }
-
-        function reflow() {
-            dragWidth = dragger.width();
-            dragHeight = dragger.height();
-            dragHelperHeight = dragHelper.height();
-            slideWidth = slider.width();
-            slideHeight = slider.height();
-            slideHelperHeight = slideHelper.height();
-
-            if (!flat) {
-                container.offset(getOffset(container, offsetElement));
-            }
-
-            updateHelperLocations();
-        }
-
-        function destroy() {
-            boundElement.show();
-            offsetElement.unbind("click.spectrum touchstart.spectrum");
-            container.remove();
-            replacer.remove();
-            spectrums[spect.id] = null;
-        }
-
-        initialize();
-
-        var spect = {
-            show: show,
-            hide: hide,
-            set: function (c) {
-                set(c, true);
-            },
-            get: get,
-            destroy: destroy,
-            container: container
-        };
-
-        spect.id = spectrums.push(spect) - 1;
-
-        return spect;
-    }
-
-    /**
-    * checkOffset - get the offset below/above and left/right element depending on screen position
-    * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
-    */
-    function getOffset(picker, input) {
-        var extraY = 0;
-        var dpWidth = picker.outerWidth();
-        var dpHeight = picker.outerHeight();
-        var inputWidth = input.outerWidth();
-        var inputHeight = input.outerHeight();
-        var doc = picker[0].ownerDocument;
-        var docElem = doc.documentElement;
-        var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
-        var viewHeight = docElem.clientHeight + $(doc).scrollTop();
-        var offset = input.offset();
-        offset.top += inputHeight;
-
-        offset.left -=
-            Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
-            Math.abs(offset.left + dpWidth - viewWidth) : 0);
-
-        offset.top -=
-            Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
-            Math.abs(dpHeight + inputHeight - extraY) : extraY));
-
-        return offset;
-    }
-
-    /** 
-    * noop - do nothing
-    */
-    function noop() {
-
-    }
-
-    /**
-    * stopPropagation - makes the code only doing this a little easier to read in line
-    */
-    function stopPropagation(e) {
-        e.stopPropagation();
-    }
-
-    /**
-    * Create a function bound to a given object
-    * Thanks to underscore.js
-    */
-    function bind(func, obj) {
-        var slice = Array.prototype.slice;
-        var args = slice.call(arguments, 2);
-        return function () {
-            return func.apply(obj, args.concat(slice.call(arguments)));
-        }
-    }
-
-    /**
-    * Lightweight drag helper.  Handles containment within the element, so that
-    * when dragging, the x is within [0,element.width] and y is within [0,element.height]
-    */
-    function draggable(element, onmove, onstart, onstop) {
-        onmove = onmove || function () { };
-        onstart = onstart || function () { };
-        onstop = onstop || function () { };
-        var doc = element.ownerDocument || document;
-        var dragging = false;
-        var offset = {};
-        var maxHeight = 0;
-        var maxWidth = 0;
-        var IE = $.browser.msie;
-        var hasTouch = ('ontouchstart' in window);
-
-        var duringDragEvents = {};
-        duringDragEvents["selectstart"] = prevent;
-        duringDragEvents["dragstart"] = prevent;
-        duringDragEvents[(hasTouch ? "touchmove" : "mousemove")] = move;
-        duringDragEvents[(hasTouch ? "touchend" : "mouseup")] = stop;
-
-        function prevent(e) {
-            if (e.stopPropagation) {
-                e.stopPropagation();
-            }
-            if (e.preventDefault) {
-                e.preventDefault();
-            }
-            e.returnValue = false;
-        }
-
-        function move(e) {
-            if (dragging) {
-                // Mouseup happened outside of window
-                if (IE && !(document.documentMode >= 9) && !e.button) {
-                    return stop();
-                }
-
-                var touches = e.originalEvent.touches;
-                var pageX = touches ? touches[0].pageX : e.pageX;
-                var pageY = touches ? touches[0].pageY : e.pageY;
-
-                var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
-                var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
-
-                if (hasTouch) {
-                    // Stop scrolling in iOS
-                    prevent(e);
-                }
-
-                onmove.apply(element, [dragX, dragY]);
-            }
-        }
-        function start(e) {
-            var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
-            var touches = e.originalEvent.touches;
-
-            if (!rightclick && !dragging) {
-                if (onstart.apply(element, arguments) !== false) {
-                    dragging = true;
-                    maxHeight = $(element).height();
-                    maxWidth = $(element).width();
-                    offset = $(element).offset();
-
-                    $(doc).bind(duringDragEvents);
-                    $(doc.body).addClass("sp-dragging");
-
-                    if (!hasTouch) {
-                        move(e);
-                    }
-                    
-                    prevent(e);
-                }
-            }
-        }
-        function stop() {
-            if (dragging) {
-                $(doc).unbind(duringDragEvents);
-                $(doc.body).removeClass("sp-dragging");
-                onstop.apply(element, arguments);
-            }
-            dragging = false;
-        }
-
-        $(element).bind(hasTouch ? "touchstart" : "mousedown", start);
-    }
-
-    function throttle(func, wait, debounce) {
-        var timeout;
-        return function () {
-            var context = this, args = arguments;
-            var throttler = function () {
-                timeout = null;
-                func.apply(context, args);
-            };
-            if (debounce) clearTimeout(timeout);
-            if (debounce || !timeout) timeout = setTimeout(throttler, wait);
-        };
-    }
-
-
-    /**
-    * Define a jQuery plugin
-    */
-    var dataID = "spectrum.id";
-    $.fn.spectrum = function (opts, extra) {
-        if (typeof opts == "string") {
-            if (opts == "get") {
-                return spectrums[this.eq(0).data(dataID)].get();
-            } else if (opts == "container") {
-                return spectrums[$(this).data(dataID)].container;
-            }
-
-            return this.each(function () {
-                var spect = spectrums[$(this).data(dataID)];
-                if (spect) {
-                    if (opts == "show") { spect.show(); }
-                    if (opts == "hide") { spect.hide(); }
-                    if (opts == "set") { spect.set(extra); }
-                    if (opts == "destroy") {
-                        spect.destroy();
-                        $(this).removeData(dataID);
-                    }
-                }
-            });
-        }
-
-        // Initializing a new one
-        return this.spectrum("destroy").each(function () {
-            var spect = spectrum(this, opts);
-            $(this).data(dataID, spect.id);
-        });
-    };
-
-    $.fn.spectrum.load = true;
-    $.fn.spectrum.loadOpts = {};
-    $.fn.spectrum.draggable = draggable;
-
-    $.fn.spectrum.processNativeColorInputs = function() {
-        var supportsColor = $("<input type='color' />")[0].type === "color";       
-        if (!supportsColor) {
-            $("input[type=color]").spectrum({
-                preferredFormat: "hex6"
-            });
-        }
-    };
-    
-    $(function () {
-        if ($.fn.spectrum.load) {
-            $.fn.spectrum.processNativeColorInputs();
-        }
-    });
-
-})(this, jQuery);
-
-
-
-
-
-
-
-// TinyColor.js - <https://github.com/bgrins/TinyColor> - 2011 Brian Grinstead - v0.5
-
-(function (window) {
-
-    var trimLeft = /^[\s,#]+/,
-    trimRight = /\s+$/,
-    tinyCounter = 0,
-    math = Math,
-    mathRound = math.round,
-    mathMin = math.min,
-    mathMax = math.max,
-    mathRandom = math.random,
-    parseFloat = window.parseFloat;
-
-    function tinycolor(color, opts) {
-
-        // If input is already a tinycolor, return itself
-        if (typeof color == "object" && color.hasOwnProperty("_tc_id")) {
-            return color;
-        }
-
-        var rgb = inputToRGB(color);
-        var r = rgb.r, g = rgb.g, b = rgb.b, a = parseFloat(rgb.a), format = rgb.format;
-
-        return {
-            ok: rgb.ok,
-            format: format,
-            _tc_id: tinyCounter++,
-            alpha: a,
-            toHsv: function () {
-                var hsv = rgbToHsv(r, g, b);
-                return { h: hsv.h, s: hsv.s, v: hsv.v, a: a };
-            },
-            toHsvString: function () {
-                var hsv = rgbToHsv(r, g, b);
-                var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
-                return (a == 1) ?
-              "hsv(" + h + ", " + s + "%, " + v + "%)" :
-              "hsva(" + h + ", " + s + "%, " + v + "%, " + a + ")";
-            },
-            toHsl: function () {
-                var hsl = rgbToHsl(r, g, b);
-                return { h: hsl.h, s: hsl.s, l: hsl.l, a: a };
-            },
-            toHslString: function () {
-                var hsl = rgbToHsl(r, g, b);
-                var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
-                return (a == 1) ?
-              "hsl(" + h + ", " + s + "%, " + l + "%)" :
-              "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")";
-            },
-            toHex: function () {
-                return rgbToHex(r, g, b);
-            },
-            toHexString: function (force6Char) {
-                return '#' + rgbToHex(r, g, b, force6Char);
-            },
-            toRgb: function () {
-                return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a };
-            },
-            toRgbString: function () {
-                return (a == 1) ?
-              "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" :
-              "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + a + ")";
-            },
-            toName: function () {
-                return hexNames[rgbToHex(r, g, b)] || false;
-            },
-            toFilter: function () {
-                var hex = rgbToHex(r, g, b);
-                var alphaHex = Math.round(parseFloat(a) * 255).toString(16);
-                return "progid:DXImageTransform.Microsoft.gradient(startColorstr=#" +
-                alphaHex + hex + ",endColorstr=#" + alphaHex + hex + ")";
-            },
-            toString: function (format) {
-                format = format || this.format;
-                var formattedString = false;
-                if (format === "rgb") {
-                    formattedString = this.toRgbString();
-                }
-                if (format === "hex") {
-                    formattedString = this.toHexString();
-                }
-                if (format === "hex6") {
-                    formattedString = this.toHexString(true);
-                }
-                if (format === "name") {
-                    formattedString = this.toName();
-                }
-                if (format === "hsl") {
-                    formattedString = this.toHslString();
-                }
-                if (format === "hsv") {
-                    formattedString = this.toHsvString();
-                }
-
-                return formattedString || this.toHexString();
-            }
-        };
-    }
-    
-    // If input is an object, force 1 into "1.0" to handle ratios properly
-    // String input requires "1.0" as input, so 1 will be treated as 1
-    tinycolor.fromRatio = function(color) {
-
-        if (typeof color == "object") {
-            for (var i in color) {
-                if (color[i] === 1) {
-                    color[i] = "1.0";
-                }
-            }
-        }
-
-        return tinycolor(color);
-
-    }
-
-    // Given a string or object, convert that input to RGB
-    // Possible string inputs:
-    //
-    //     "red"
-    //     "#f00" or "f00"
-    //     "#ff0000" or "ff0000"
-    //     "rgb 255 0 0" or "rgb (255, 0, 0)"
-    //     "rgb 1.0 0 0" or "rgb (1, 0, 0)"
-    //     "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
-    //     "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" 
-    //     "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
-    //     "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
-    //     "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
-    //
-    function inputToRGB(color) {
-
-        var rgb = { r: 0, g: 0, b: 0 };
-        var a = 1;
-        var ok = false;
-        var format = false;
-
-        if (typeof color == "string") {
-            color = stringInputToObject(color);
-        }
-
-        if (typeof color == "object") {
-            if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
-                rgb = rgbToRgb(color.r, color.g, color.b);
-                ok = true;
-                format = "rgb";
-            }
-            else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
-                rgb = hsvToRgb(color.h, color.s, color.v);
-                ok = true;
-                format = "hsv";
-            }
-            else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
-                var rgb = hslToRgb(color.h, color.s, color.l);
-                ok = true;
-                format = "hsl";
-            }
-
-            if (color.hasOwnProperty("a")) {
-                a = color.a;
-            }
-        }
-
-        rgb.r = mathMin(255, mathMax(rgb.r, 0));
-        rgb.g = mathMin(255, mathMax(rgb.g, 0));
-        rgb.b = mathMin(255, mathMax(rgb.b, 0));
-
-
-        // Don't let the range of [0,255] come back in [0,1].  
-        // Potentially lose a little bit of precision here, but will fix issues where
-        // .5 gets interpreted as half of the total, instead of half of 1.
-        // If it was supposed to be 128, this was already taken care of in the conversion function
-        if (rgb.r < 1) { rgb.r = mathRound(rgb.r); }
-        if (rgb.g < 1) { rgb.g = mathRound(rgb.g); }
-        if (rgb.b < 1) { rgb.b = mathRound(rgb.b); }
-
-        return {
-            ok: ok,
-            format: (color && color.format) || format,
-            r: rgb.r,
-            g: rgb.g,
-            b: rgb.b,
-            a: a
-        };
-    }
-
-
-
-    // Conversion Functions
-    // --------------------
-
-    // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:   
-    // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
-
-    // `rgbToRgb`  
-    // Handle bounds / percentage checking to conform to CSS color spec
-    // <http://www.w3.org/TR/css3-color/>  
-    // *Assumes:* r, g, b in [0, 255] or [0, 1]  
-    // *Returns:* { r, g, b } in [0, 255]
-    function rgbToRgb(r, g, b) {
-        return {
-            r: bound01(r, 255) * 255,
-            g: bound01(g, 255) * 255,
-            b: bound01(b, 255) * 255
-        };
-    }
-
-    // `rgbToHsl`  
-    // Converts an RGB color value to HSL.  
-    // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]  
-    // *Returns:* { h, s, l } in [0,1]  
-    function rgbToHsl(r, g, b) {
-
-        r = bound01(r, 255);
-        g = bound01(g, 255);
-        b = bound01(b, 255);
-
-        var max = mathMax(r, g, b), min = mathMin(r, g, b);
-        var h, s, l = (max + min) / 2;
-
-        if (max == min) {
-            h = s = 0; // achromatic
-        }
-        else {
-            var d = max - min;
-            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
-            switch (max) {
-                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
-                case g: h = (b - r) / d + 2; break;
-                case b: h = (r - g) / d + 4; break;
-            }
-
-            h /= 6;
-        }
-
-        return { h: h, s: s, l: l };
-    }
-
-    // `hslToRgb`  
-    // Converts an HSL color value to RGB.  
-    // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]  
-    // *Returns:* { r, g, b } in the set [0, 255]  
-    function hslToRgb(h, s, l) {
-        var r, g, b;
-
-        h = bound01(h, 360);
-        s = bound01(s, 100);
-        l = bound01(l, 100);
-
-        function hue2rgb(p, q, t) {
-            if (t < 0) t += 1;
-            if (t > 1) t -= 1;
-            if (t < 1 / 6) return p + (q - p) * 6 * t;
-            if (t < 1 / 2) return q;
-            if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
-            return p;
-        }
-
-        if (s == 0) {
-            r = g = b = l; // achromatic
-        }
-        else {
-            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
-            var p = 2 * l - q;
-            r = hue2rgb(p, q, h + 1 / 3);
-            g = hue2rgb(p, q, h);
-            b = hue2rgb(p, q, h - 1 / 3);
-        }
-
-        return { r: r * 255, g: g * 255, b: b * 255 };
-    }
-
-    // `rgbToHsv`  
-    // Converts an RGB color value to HSV  
-    // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]  
-    // *Returns:* { h, s, v } in [0,1]  
-    function rgbToHsv(r, g, b) {
-
-        r = bound01(r, 255);
-        g = bound01(g, 255);
-        b = bound01(b, 255);
-
-        var max = mathMax(r, g, b), min = mathMin(r, g, b);
-        var h, s, v = max;
-
-        var d = max - min;
-        s = max == 0 ? 0 : d / max;
-
-        if (max == min) {
-            h = 0; // achromatic
-        }
-        else {
-            switch (max) {
-                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
-                case g: h = (b - r) / d + 2; break;
-                case b: h = (r - g) / d + 4; break;
-            }
-            h /= 6;
-        }
-        return { h: h, s: s, v: v };
-    }
-
-    // `hsvToRgb`  
-    // Converts an HSV color value to RGB. 
-    // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
-    // *Returns:* { r, g, b } in the set [0, 255]
-    function hsvToRgb(h, s, v) {
-        var r, g, b;
-
-        h = bound01(h, 360) * 6;
-        s = bound01(s, 100);
-        v = bound01(v, 100);
-
-        var i = math.floor(h),
-        f = h - i,
-        p = v * (1 - s),
-        q = v * (1 - f * s),
-        t = v * (1 - (1 - f) * s),
-        mod = i % 6,
-        r = [v, q, p, p, t, v][mod],
-        g = [t, v, v, q, p, p][mod],
-        b = [p, p, t, v, v, q][mod];
-
-        return { r: r * 255, g: g * 255, b: b * 255 };
-    }
-
-    // `rgbToHex`  
-    // Converts an RGB color to hex  
-    // Assumes r, g, and b are contained in the set [0, 255]  
-    // Returns a 3 or 6 character hex  
-    function rgbToHex(r, g, b, force6Char) {
-        function pad(c) {
-            return c.length == 1 ? '0' + c : '' + c;
-        }
-
-        var hex = [
-            pad(mathRound(r).toString(16)),
-            pad(mathRound(g).toString(16)),
-            pad(mathRound(b).toString(16))
-        ];
-
-        // Return a 3 character hex if possible
-        if (!force6Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
-            return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
-        }
-
-        return hex.join("");
-    }
-
-    // `equals`  
-    // Can be called with any tinycolor input
-    tinycolor.equals = function (color1, color2) {
-        if (!color1 || !color2) { return false; }
-        return tinycolor(color1).toHex() == tinycolor(color2).toHex();
-    };
-    tinycolor.random = function () {
-        return tinycolor.fromRatio({
-            r: mathRandom(),
-            g: mathRandom(),
-            b: mathRandom()
-        });
-    };
-
-
-    // Modification Functions
-    // ----------------------
-    // Thanks to less.js for some of the basics here  
-    // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
-
-
-    tinycolor.desaturate = function (color, amount) {
-        var hsl = tinycolor(color).toHsl();
-        hsl.s -= ((amount || 10) / 100);
-        hsl.s = clamp01(hsl.s);
-        return tinycolor(hsl);
-    };
-    tinycolor.saturate = function (color, amount) {
-        var hsl = tinycolor(color).toHsl();
-        hsl.s += ((amount || 10) / 100);
-        hsl.s = clamp01(hsl.s);
-        return tinycolor(hsl);
-    };
-    tinycolor.greyscale = function (color) {
-        return tinycolor.desaturate(color, 100);
-    };
-    tinycolor.lighten = function (color, amount) {
-        var hsl = tinycolor(color).toHsl();
-        hsl.l += ((amount || 10) / 100);
-        hsl.l = clamp01(hsl.l);
-        return tinycolor(hsl);
-    };
-    tinycolor.darken = function (color, amount) {
-        var hsl = tinycolor(color).toHsl();
-        hsl.l -= ((amount || 10) / 100);
-        hsl.l = clamp01(hsl.l);
-        return tinycolor(hsl);
-    };
-    tinycolor.complement = function (color) {
-        var hsl = tinycolor(color).toHsl();
-        hsl.h = (hsl.h + .5) % 1;
-        return tinycolor(hsl);
-    };
-
-
-    // Combination Functions
-    // ---------------------
-    // Thanks to jQuery xColor for some of the ideas behind these
-    // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
-
-    tinycolor.triad = function (color) {
-        var hsl = tinycolor(color).toHsl();
-        var h = hsl.h * 360;
-        return [
-        tinycolor(color),
-        tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
-        tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
-    ];
-    };
-    tinycolor.tetrad = function (color) {
-        var hsl = tinycolor(color).toHsl();
-        var h = hsl.h * 360;
-        return [
-        tinycolor(color),
-        tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
-        tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
-        tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
-    ];
-    };
-    tinycolor.splitcomplement = function (color) {
-        var hsl = tinycolor(color).toHsl();
-        var h = hsl.h * 360;
-        return [
-        tinycolor(color),
-        tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }),
-        tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l })
-    ];
-    };
-    tinycolor.analogous = function (color, results, slices) {
-        results = results || 6;
-        slices = slices || 30;
-
-        var hsl = tinycolor(color).toHsl();
-        var part = 360 / slices
-        var ret = [tinycolor(color)];
-
-        hsl.h *= 360;
-
-        for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
-            hsl.h = (hsl.h + part) % 360;
-            ret.push(tinycolor(hsl));
-        }
-        return ret;
-    };
-    tinycolor.monochromatic = function (color, results) {
-        results = results || 6;
-        var hsv = tinycolor(color).toHsv();
-        var h = hsv.h, s = hsv.s, v = hsv.v;
-        var ret = [];
-        var modification = 1 / results;
-
-        while (results--) {
-            ret.push(tinycolor({ h: h, s: s, v: v }));
-            v = (v + modification) % 1;
-        }
-
-        return ret;
-    };
-    tinycolor.readable = function (color1, color2) {
-        var a = tinycolor(color1).toRgb(), b = tinycolor(color2).toRgb();
-        return (
-        (b.r - a.r) * (b.r - a.r) +
-        (b.g - a.g) * (b.g - a.g) +
-        (b.b - a.b) * (b.b - a.b)
-    ) > 0x28A4;
-    };
-
-    // Big List of Colors
-    // ---------
-    // <http://www.w3.org/TR/css3-color/#svg-color>
-    var names = tinycolor.names = {
-        aliceblue: "f0f8ff",
-        antiquewhite: "faebd7",
-        aqua: "0ff",
-        aquamarine: "7fffd4",
-        azure: "f0ffff",
-        beige: "f5f5dc",
-        bisque: "ffe4c4",
-        black: "000",
-        blanchedalmond: "ffebcd",
-        blue: "00f",
-        blueviolet: "8a2be2",
-        brown: "a52a2a",
-        burlywood: "deb887",
-        burntsienna: "ea7e5d",
-        cadetblue: "5f9ea0",
-        chartreuse: "7fff00",
-        chocolate: "d2691e",
-        coral: "ff7f50",
-        cornflowerblue: "6495ed",
-        cornsilk: "fff8dc",
-        crimson: "dc143c",
-        cyan: "0ff",
-        darkblue: "00008b",
-        darkcyan: "008b8b",
-        darkgoldenrod: "b8860b",
-        darkgray: "a9a9a9",
-        darkgreen: "006400",
-        darkgrey: "a9a9a9",
-        darkkhaki: "bdb76b",
-        darkmagenta: "8b008b",
-        darkolivegreen: "556b2f",
-        darkorange: "ff8c00",
-        darkorchid: "9932cc",
-        darkred: "8b0000",
-        darksalmon: "e9967a",
-        darkseagreen: "8fbc8f",
-        darkslateblue: "483d8b",
-        darkslategray: "2f4f4f",
-        darkslategrey: "2f4f4f",
-        darkturquoise: "00ced1",
-        darkviolet: "9400d3",
-        deeppink: "ff1493",
-        deepskyblue: "00bfff",
-        dimgray: "696969",
-        dimgrey: "696969",
-        dodgerblue: "1e90ff",
-        firebrick: "b22222",
-        floralwhite: "fffaf0",
-        forestgreen: "228b22",
-        fuchsia: "f0f",
-        gainsboro: "dcdcdc",
-        ghostwhite: "f8f8ff",
-        gold: "ffd700",
-        goldenrod: "daa520",
-        gray: "808080",
-        green: "008000",
-        greenyellow: "adff2f",
-        grey: "808080",
-        honeydew: "f0fff0",
-        hotpink: "ff69b4",
-        indianred: "cd5c5c",
-        indigo: "4b0082",
-        ivory: "fffff0",
-        khaki: "f0e68c",
-        lavender: "e6e6fa",
-        lavenderblush: "fff0f5",
-        lawngreen: "7cfc00",
-        lemonchiffon: "fffacd",
-        lightblue: "add8e6",
-        lightcoral: "f08080",
-        lightcyan: "e0ffff",
-        lightgoldenrodyellow: "fafad2",
-        lightgray: "d3d3d3",
-        lightgreen: "90ee90",
-        lightgrey: "d3d3d3",
-        lightpink: "ffb6c1",
-        lightsalmon: "ffa07a",
-        lightseagreen: "20b2aa",
-        lightskyblue: "87cefa",
-        lightslategray: "789",
-        lightslategrey: "789",
-        lightsteelblue: "b0c4de",
-        lightyellow: "ffffe0",
-        lime: "0f0",
-        limegreen: "32cd32",
-        linen: "faf0e6",
-        magenta: "f0f",
-        maroon: "800000",
-        mediumaquamarine: "66cdaa",
-        mediumblue: "0000cd",
-        mediumorchid: "ba55d3",
-        mediumpurple: "9370db",
-        mediumseagreen: "3cb371",
-        mediumslateblue: "7b68ee",
-        mediumspringgreen: "00fa9a",
-        mediumturquoise: "48d1cc",
-        mediumvioletred: "c71585",
-        midnightblue: "191970",
-        mintcream: "f5fffa",
-        mistyrose: "ffe4e1",
-        moccasin: "ffe4b5",
-        navajowhite: "ffdead",
-        navy: "000080",
-        oldlace: "fdf5e6",
-        olive: "808000",
-        olivedrab: "6b8e23",
-        orange: "ffa500",
-        orangered: "ff4500",
-        orchid: "da70d6",
-        palegoldenrod: "eee8aa",
-        palegreen: "98fb98",
-        paleturquoise: "afeeee",
-        palevioletred: "db7093",
-        papayawhip: "ffefd5",
-        peachpuff: "ffdab9",
-        peru: "cd853f",
-        pink: "ffc0cb",
-        plum: "dda0dd",
-        powderblue: "b0e0e6",
-        purple: "800080",
-        red: "f00",
-        rosybrown: "bc8f8f",
-        royalblue: "4169e1",
-        saddlebrown: "8b4513",
-        salmon: "fa8072",
-        sandybrown: "f4a460",
-        seagreen: "2e8b57",
-        seashell: "fff5ee",
-        sienna: "a0522d",
-        silver: "c0c0c0",
-        skyblue: "87ceeb",
-        slateblue: "6a5acd",
-        slategray: "708090",
-        slategrey: "708090",
-        snow: "fffafa",
-        springgreen: "00ff7f",
-        steelblue: "4682b4",
-        tan: "d2b48c",
-        teal: "008080",
-        thistle: "d8bfd8",
-        tomato: "ff6347",
-        turquoise: "40e0d0",
-        violet: "ee82ee",
-        wheat: "f5deb3",
-        white: "fff",
-        whitesmoke: "f5f5f5",
-        yellow: "ff0",
-        yellowgreen: "9acd32"
-    };
-
-    // Make it easy to access colors via `hexNames[hex]`
-    var hexNames = tinycolor.hexNames = flip(names);
-
-
-    // Utilities
-    // ---------
-
-    // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
-    function flip(o) {
-        var flipped = {};
-        for (var i in o) {
-            if (o.hasOwnProperty(i)) {
-                flipped[o[i]] = i;
-            }
-        }
-        return flipped;
-    }
-
-    // Take input from [0, n] and return it as [0, 1]
-    function bound01(n, max) {
-        if (isOnePointZero(n)) { n = "100%"; }
-
-        var processPercent = isPercentage(n);
-        n = mathMin(max, mathMax(0, parseFloat(n)));
-
-        // Automatically convert percentage into number
-        if (processPercent) {
-            n = n * (max / 100);
-        }
-
-        // Handle floating point rounding errors
-        if ((math.abs(n - max) < 0.000001)) {
-            return 1;
-        }
-        else if (n >= 1) {
-            return (n % max) / parseFloat(max);
-        }
-        return n;
-    }
-
-    // Force a number between 0 and 1
-    function clamp01(val) {
-        return mathMin(1, mathMax(0, val));
-    }
-
-    // Parse an integer into hex
-    function parseHex(val) {
-        return parseInt(val, 16);
-    }
-
-    // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
-    // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
-    function isOnePointZero(n) {
-        return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
-    }
-
-    // Check to see if string passed in is a percentage
-    function isPercentage(n) {
-        return typeof n === "string" && n.indexOf('%') != -1;
-    }
-
-    var matchers = (function () {
-
-        // <http://www.w3.org/TR/css3-values/#integers>
-        var CSS_INTEGER = "[-\\+]?\\d+%?";
-
-        // <http://www.w3.org/TR/css3-values/#number-value>
-        var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
-
-        // Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.
-        var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
-
-        // Actual matching.  
-        // Parentheses and commas are optional, but not required.  
-        // Whitespace can take the place of commas or opening paren
-        var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
-        var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
-
-        return {
-            rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
-            rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
-            hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
-            hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
-            hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
-            hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
-            hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
-        };
-    })();
-
-    // `stringInputToObject`  
-    // Permissive string parsing.  Take in a number of formats, and output an object
-    // based on detected format.  Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
-    function stringInputToObject(color) {
-
-        color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
-        var named = false;
-        if (names[color]) {
-            color = names[color];
-            named = true;
-        }
-        else if (color == 'transparent') {
-            return { r: 0, g: 0, b: 0, a: 0 };
-        }
-
-        // Try to match string input using regular expressions.  
-        // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]  
-        // Just return an object and let the conversion functions handle that.  
-        // This way the result will be the same whether the tinycolor is initialized with string or object.
-        var match;
-        if ((match = matchers.rgb.exec(color))) {
-            return { r: match[1], g: match[2], b: match[3] };
-        }
-        if ((match = matchers.rgba.exec(color))) {
-            return { r: match[1], g: match[2], b: match[3], a: match[4] };
-        }
-        if ((match = matchers.hsl.exec(color))) {
-            return { h: match[1], s: match[2], l: match[3] };
-        }
-        if ((match = matchers.hsla.exec(color))) {
-            return { h: match[1], s: match[2], l: match[3], a: match[4] };
-        }
-        if ((match = matchers.hsv.exec(color))) {
-            return { h: match[1], s: match[2], v: match[3] };
-        }
-        if ((match = matchers.hex6.exec(color))) {
-            return {
-                r: parseHex(match[1]),
-                g: parseHex(match[2]),
-                b: parseHex(match[3]),
-                format: named ? "name" : "hex"
-            };
-        }
-        if ((match = matchers.hex3.exec(color))) {
-            return {
-                r: parseHex(match[1] + '' + match[1]),
-                g: parseHex(match[2] + '' + match[2]),
-                b: parseHex(match[3] + '' + match[3]),
-                format: named ? "name" : "hex"
-            };
-        }
-
-        return false;
-    }
-
-    // Everything is ready, expose to window
-    window.tinycolor = tinycolor;
-
-})(this);
-
diff --git a/emperor/support_files/js/trajectory.js b/emperor/support_files/js/trajectory.js
new file mode 100644
index 0000000..ca4df5b
--- /dev/null
+++ b/emperor/support_files/js/trajectory.js
@@ -0,0 +1,406 @@
+/** @module trajectory */
+define([
+    'underscore'
+], function(_) {
+  /**
+   *
+   * @class TrajectoryOfSamples
+   *
+   * Represents an ordered set of samples and their position in PCoA space.
+   *
+   * @param {string[]} sampleNames Array of sample identifiers.
+   * @param {string} metadataCategoryName The name of the category in the
+   * mapping file used to generate this trajectory.
+   * @param {float[]} gradientPoints The position of the samples in the
+   * gradient.
+   * @param {Object[]} coordinates Array of objects with x, y and z properties
+   * where each corresponds to the position of a sample in PCoA space.
+   * @param {float} minimumDelta Minimum differential between the ordered
+   * gradientPoints this value must be non-zero. Note that this value should be
+   * computed taking into account all the other trajectories that will be
+   * animated together, usually by an AnimationDirector object.
+   * @param {integer} [suppliedN = 5] Determines how many points should be found
+   * in the the trajectory.
+   * @param {integer} [maxN = 10] Maximum number of samples allowed per
+   * interpolation interval.
+   *
+   * @return {TrajectoryOfSamples} An instance of TrajectoryOfSamples
+   * @constructs TrajectoryOfSamples
+   **/
+  function TrajectoryOfSamples(sampleNames, metadataCategoryName,
+                               gradientPoints, coordinates, minimumDelta,
+                               suppliedN, maxN) {
+    /**
+     * Sample identifiers
+     * @type {string[]}
+     */
+    this.sampleNames = sampleNames;
+    /**
+     * The name of the category in the mapping file used to generate this
+     * trajectory.
+     * @type {string}
+     */
+    this.metadataCategoryName = metadataCategoryName;
+
+    // array of the values that samples have through the gradient
+    this.gradientPoints = gradientPoints;
+
+    // the first three axes of the data points
+    this.coordinates = coordinates;
+
+    /**
+     * Minimum differential between samples in the trajectory; the value is
+     * computed using the gradientPoints array.
+     * @type {float}
+     */
+    this.minimumDelta = minimumDelta;
+
+    /**
+     * Minimum number of frames a distance will have in the gradient.
+     * This value determines how fast the animation will run.
+     * For now we use 5 as a good default value; 60 was way too slow.
+     * @type {float}
+     * @default 5
+     */
+    this.suppliedN = suppliedN !== undefined ? suppliedN : 5;
+    /**
+     * Maximum number of samples allowed per interpolation interval.
+     * @type {float}
+     * @default 10
+     */
+    this.maxN = maxN !== undefined ? maxN : 10;
+
+    if (this.coordinates.length != this.gradientPoints.length) {
+      throw new Error('The number of coordinate points and gradient points is' +
+          'different, make sure these values are consistent.');
+    }
+
+    // initialize as an empty array but fill it up upon request
+    /**
+     * Array of objects with the corresponding interpolated x, y and z values.
+     * The interpolation operation takes place between subsequent samples.
+     * @type {Object[]}
+     */
+    this.interpolatedCoordinates = null;
+    this._generateInterpolatedCoordinates();
+
+    return this;
+  }
+
+  /**
+   *
+   * Helper method to iterate over all the coordinates and generate
+   * interpolated arrays.
+   * @private
+   *
+   */
+  TrajectoryOfSamples.prototype._generateInterpolatedCoordinates = function() {
+    var pointsPerStep = 0, delta = 0;
+    var interpolatedCoordinatesBuffer = new Array(),
+    intervalBuffer = new Array();
+    var currInterpolation;
+
+    // iterate over the gradient points to compute the interpolated distances
+    for (var index = 0; index < this.gradientPoints.length - 1; index++) {
+
+      // calculate the absolute difference of the current pair of points
+      delta = Math.abs(Math.abs(this.gradientPoints[index]) - Math.abs(
+            this.gradientPoints[index + 1]));
+
+      pointsPerStep = this.calculateNumberOfPointsForDelta(delta);
+      if (pointsPerStep > this.maxN) {
+        pointsPerStep = this.maxN;
+      }
+
+      currInterpolation = linearInterpolation(this.coordinates[index]['x'],
+          this.coordinates[index]['y'],
+          this.coordinates[index]['z'],
+          this.coordinates[index + 1]['x'],
+          this.coordinates[index + 1]['y'],
+          this.coordinates[index + 1]['z'],
+          pointsPerStep);
+
+      // extend to include these interpolated points, do not include the last
+      // element of the array to avoid repeating the number per interval
+      interpolatedCoordinatesBuffer = interpolatedCoordinatesBuffer.concat(
+          currInterpolation.slice(0, -1));
+
+      // extend the interval buffer
+      // credit goes to http://stackoverflow.com/a/13735425/379593
+      intervalBuffer = intervalBuffer.concat(
+          Array.apply(null, new Array(pointsPerStep)).map(
+            Number.prototype.valueOf, index));
+
+    }
+
+    // add the last point to make sure the trajectory is closed
+    this.interpolatedCoordinates = interpolatedCoordinatesBuffer.concat(
+        currInterpolation.slice(-1));
+    this._intervalValues = intervalBuffer;
+
+    return;
+  };
+
+  /**
+   *
+   * Helper method to calculate the number of points that there should be for a
+   * differential.
+   *
+   * @param {float} delta Value for which to determine the required number of
+   * points.
+   *
+   * @return {integer} The number of suggested frames for the differential
+   *
+   */
+  TrajectoryOfSamples.prototype.calculateNumberOfPointsForDelta =
+      function(delta) {
+    return Math.floor((delta * this.suppliedN) / this.minimumDelta);
+  };
+
+  /**
+   *
+   * Retrieve the representative coordinates needed for a trajectory to be
+   * drawn.
+   *
+   ** Note that this implementation is naive and will return points that lay on
+   * a rect line if these were part of the original set of coordinates.
+   *
+   * @param {integer} idx Value for which to determine the required number of
+   * points.
+   *
+   * @return {Array[]} Array containing the representative float x, y, z
+   * coordinates needed to draw a trajectory at the given index.
+   */
+  TrajectoryOfSamples.prototype.representativeCoordinatesAtIndex =
+      function(idx) {
+
+    if (idx === 0) {
+      return [this.coordinates[0]];
+    }
+
+    // we only need to show the edges and none of the interpolated points
+    if (this.interpolatedCoordinates.length - 1 <= idx) {
+      return this.coordinates;
+    }
+
+    var output = this.coordinates.slice(0, this._intervalValues[idx] + 1);
+    output = output.concat(this.interpolatedCoordinates[idx]);
+
+    return output;
+  };
+
+  /**
+   *
+   * Function to interpolate a certain number of steps between two three
+   * dimensional points.
+   *
+   * This code is based on the function found in:
+   *     http://snipplr.com/view.php?codeview&id=47206
+   *
+   * @param {float} x_1 Initial value of a position in the first dimension
+   * @param {float} y_1 Initial value of a position in the second dimension
+   * @param {float} z_1 Initial value of a position in the third dimension
+   * @param {float} x_2 Final value of a position in the first dimension
+   * @param {float} y_2 Final value of a position in the second dimension
+   * @param {float} z_2 Final value of a position in the third dimension
+   * @param {integer} steps Number of steps that we want the interpolation to
+   * run
+   *
+   * @return {Object[]} Array of objects that have the x, y and z attributes
+   * @function linearInterpolation
+   *
+   */
+
+  function linearInterpolation(x_1, y_1, z_1, x_2, y_2, z_2, steps) {
+    var xAbs = Math.abs(x_1 - x_2);
+    var yAbs = Math.abs(y_1 - y_2);
+    var zAbs = Math.abs(z_1 - z_2);
+    var xDiff = x_2 - x_1;
+    var yDiff = y_2 - y_1;
+    var zDiff = z_2 - z_1;
+
+    // and apparetnly this makes takes no effect whatsoever
+    var length = Math.sqrt(xAbs * xAbs + yAbs * yAbs + zAbs * zAbs);
+    var xStep = xDiff / steps;
+    var yStep = yDiff / steps;
+    var zStep = zDiff / steps;
+
+    var newx = 0;
+    var newy = 0;
+    var newz = 0;
+    var result = new Array();
+
+    for (var s = 0; s <= steps; s++) {
+      newx = x_1 + (xStep * s);
+      newy = y_1 + (yStep * s);
+      newz = z_1 + (zStep * s);
+
+      result.push({'x': newx, 'y': newy, 'z': newz});
+    }
+
+    return result;
+  }
+
+  /**
+   *
+   * Function to compute the distance between two three dimensional points.
+   *
+   * This code is based on the function found in:
+   *     {@link http://snipplr.com/view.php?codeview&id=47207}
+   *
+   * @param {float} x_1 Initial value of a position in the first dimension
+   * @param {float} y_1 Initial value of a position in the second dimension
+   * @param {float} z_1 Initial value of a position in the third dimension
+   * @param {float} x_2 Final value of a position in the first dimension
+   * @param {float} y_2 Final value of a position in the second dimension
+   * @param {float} z_2 Final value of a position in the third dimension
+   *
+   * @return {float} Value of the distance between the two points
+   * @function distanceBetweenPoints
+   *
+   */
+  function distanceBetweenPoints(x_1, y_1, z_1, x_2, y_2, z_2) {
+    var xs = 0;
+    var ys = 0;
+    var zs = 0;
+
+    // Math.pow is faster than simple multiplication
+    xs = Math.pow(Math.abs(x_2 - x_1), 2);
+    ys = Math.pow(Math.abs(y_2 - y_1), 2);
+    zs = Math.pow(Math.abs(z_2 - z_1), 2);
+
+    return Math.sqrt(xs + ys + zs);
+  }
+
+  /**
+   *
+   * Helper data wrangling function, takes as inputs a mapping file and the
+   * coordinates to synthesize the information into an array. Mainly used by
+   * the AnimationDirector object.
+   *
+   * @param {string[]} mappingFileHeaders The metadata mapping file headers.
+   * @param {Array[]} mappingFileData An Array where the indices are sample
+   * identifiers and each of the contained elements is an Array of strings where
+   * the first element corresponds to the first data for the first column in the
+   * mapping file (`mappingFileHeaders`).
+   * @param {Object[]} coordinatesData An Array of Objects where the indices are
+   * the sample identifiers and each of the objects has the following
+   * properties: x, y, z, name, color, P1, P2, P3, ... PN where N is the number
+   * of dimensions in this dataset.
+   * @param {string} trajectoryCategory a string with the name of the mapping
+   * file header where the data that groups the samples is contained, this will
+   * usually be BODY_SITE, HOST_SUBJECT_ID, etc..
+   * @param {string} gradientCategory a string with the name of the mapping file
+   * header where the data that spreads the samples over a gradient is
+   * contained, usually time or days_since_epoch. Note that this should be an
+   * all numeric category.
+   *
+   * @return {Object[]} An Array with the contained data indexed by the sample
+   * identifiers.
+   * @throws {Error} Any of the following:
+   *  * gradientIndex === -1
+   *  * trajectoryIndex === -1
+   * @function getSampleNamesAndDataForSortedTrajectories
+   *
+   */
+  function getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+      mappingFileData,
+      coordinatesData,
+      trajectoryCategory,
+      gradientCategory) {
+    var gradientIndex = mappingFileHeaders.indexOf(gradientCategory);
+    var trajectoryIndex = mappingFileHeaders.indexOf(trajectoryCategory);
+
+    var chewedSampleData = new Object();
+    var trajectoryBuffer = null, gradientBuffer = null;
+
+    // this is the most utterly annoying thing ever
+    if (gradientIndex === -1) {
+      throw new Error('Gradient category not found in mapping file header');
+    }
+    if (trajectoryIndex === -1) {
+      throw new Error('Trajectory category not found in mapping file header');
+    }
+
+    for (var sampleId in mappingFileData) {
+
+      trajectoryBuffer = mappingFileData[sampleId][trajectoryIndex];
+      gradientBuffer = mappingFileData[sampleId][gradientIndex];
+
+      // check if there's already an element for this trajectory, if not
+      // initialize a new array for this element of the processed data
+      if (chewedSampleData[trajectoryBuffer] === undefined) {
+        chewedSampleData[trajectoryBuffer] = new Array();
+      }
+      chewedSampleData[trajectoryBuffer].push({'name': sampleId,
+        'value': gradientBuffer, 'x': coordinatesData[sampleId]['x'],
+        'y': coordinatesData[sampleId]['y'],
+        'z': coordinatesData[sampleId]['z']});
+    }
+
+    // we need this custom sorting function to make the values be sorted in
+    // ascending order but accounting for the data structure that we just built
+    var sortingFunction = function(a, b) {
+      return parseFloat(a['value']) - parseFloat(b['value']);
+    };
+
+    // sort all the values using the custom anonymous function
+    for (var key in chewedSampleData) {
+      chewedSampleData[key].sort(sortingFunction);
+    }
+
+    return chewedSampleData;
+  }
+
+  /**
+   *
+   * Function to calculate the minimum delta from an array of wrangled data by
+   * getSampleNamesAndDataForSortedTrajectories.
+   *
+   * This function will not take into account as a minimum delta zero values
+   * i.e. the differential between two samples that lie at the same position in
+   * the gradient.
+   *
+   * @param {Object[]} sampleData An Array as computed from mapping file data
+   * and coordinates by getSampleNamesAndDataForSortedTrajectories.
+   *
+   * @return {float} The minimum difference between two samples across the
+   * defined gradient.
+   *
+   * @throws {Error} Input data is undefined.
+   * @function getMinimumDelta
+   */
+  function getMinimumDelta(sampleData) {
+    if (sampleData === undefined) {
+      throw new Error('The sample data cannot be undefined');
+    }
+
+    var bufferArray = new Array(), deltasArray = new Array();
+
+    // go over all the data and compute the deltas for all trajectories
+    for (var key in sampleData) {
+      for (var index = 0; index < sampleData[key].length; index++) {
+        bufferArray.push(sampleData[key][index]['value']);
+      }
+      for (var index = 0; index < bufferArray.length - 1; index++) {
+        deltasArray.push(Math.abs(bufferArray[index + 1] - bufferArray[index]));
+      }
+
+      // clean buffer array
+      bufferArray.length = 0;
+    }
+
+    // remove all the deltas of zero so we don't skew our results
+    deltasArray = _.filter(deltasArray, function(num) { return num !== 0; });
+
+    // return the minimum of these values
+    return _.min(deltasArray);
+  }
+
+  return {'TrajectoryOfSamples': TrajectoryOfSamples,
+    'getMinimumDelta': getMinimumDelta,
+    'getSampleNamesAndDataForSortedTrajectories':
+      getSampleNamesAndDataForSortedTrajectories,
+    'distanceBetweenPoints': distanceBetweenPoints,
+    'linearInterpolation': linearInterpolation};
+});
diff --git a/emperor/support_files/js/util.js b/emperor/support_files/js/util.js
new file mode 100644
index 0000000..a71ced2
--- /dev/null
+++ b/emperor/support_files/js/util.js
@@ -0,0 +1,147 @@
+/** @module utility-functions */
+define(['underscore'], function(_) {
+  /**
+   *
+   * Sorting function that deals with alpha and numeric elements.
+   *
+   * @param {String[]} list A list of strings to sort
+   *
+   * @return {String[]} The sorted list of strings
+   * @function naturalSort
+   */
+  function naturalSort(list) {
+    var numericPart = [], alphaPart = [], result = [];
+
+    // separate the numeric and the alpha elements of the array
+    for (var index = 0; index < list.length; index++) {
+      if (isNaN(parseFloat(list[index]))) {
+        alphaPart.push(list[index]);
+      }
+      else {
+        numericPart.push(list[index]);
+      }
+    }
+
+    // ignore casing of the strings, taken from:
+    // http://stackoverflow.com/a/9645447/379593
+    alphaPart.sort(function(a, b) {
+      return a.toLowerCase().localeCompare(b.toLowerCase());
+    });
+
+    // sort in ascending order
+    numericPart.sort(function(a, b) {return parseFloat(a) - parseFloat(b)});
+
+      return result.concat(alphaPart, numericPart);
+  }
+
+
+  /**
+   *
+   * Utility function that splits the lineage into taxonomic levels
+   * and returns the taxonomic level specified
+   *
+   * @param {String} lineage The taxonomic string, with levels seperated by
+   * semicolons.
+   * @param {Integer} levelIndex The taxonomic level to truncate to.
+   * 1 = Kingdom, 2 = Phylum, etc.
+   *
+   * @return {String} The taxonomic string truncated to desired level.
+   * @function truncateLevel
+   */
+  function truncateLevel(lineage, levelIndex) {
+    if (levelIndex === 0) {
+      return lineage;
+    }
+    var levels = lineage.split(';');
+    var taxaLabel = '';
+    for (var i = 0; (i < levelIndex && i < levels.length); i++) {
+      var level = levels[i];
+      if (level[level.length - 1] == '_') {
+        taxaLabel += ';' + level;
+      }else {
+        taxaLabel = level;
+      }
+    }
+    return taxaLabel;
+  }
+
+  /**
+   *
+   * Utility function to convert an XML DOM documents to a string useful for
+   * unit testing. This code is based on
+   * [this SO answer]{@link http://stackoverflow.com/a/1750890}
+   *
+   * @param {Node} node XML DOM object, usually as created by the document
+   * object.
+   *
+   * @return {String} Representation of the node object.
+   * @function convertXMLToString
+   */
+  function convertXMLToString(node) {
+    if (typeof(XMLSerializer) !== 'undefined') {
+      var serializer = new XMLSerializer();
+      return serializer.serializeToString(node);
+    }
+    else if (node.xml) {
+      return node.xml;
+    }
+  }
+
+  /**
+   *
+   * Split list of string values into numeric and non-numeric values
+   * @param {String[]} values The values to check
+   * @return {Object} Object with two keys, `numeric` and `nonNumeric`. Numeric
+   * holds an array of all numeric values fownd, converted to numbers.
+   * nonNumeric holds an array of the remaining values, still as strings.
+   */
+   function splitNumericValues(values) {
+    var numeric = [];
+    var nonNumeric = [];
+    _.each(values, function(element) {
+        // http://stackoverflow.com/a/9716488
+        if (!isNaN(parseFloat(element)) && isFinite(element)) {
+          numeric.push(+element);
+        }
+        else {
+          nonNumeric.push(element);
+        }
+      });
+    return {numeric: numeric, nonNumeric: nonNumeric};
+   }
+
+  /**
+   *
+   * Escape special characters in a string for use in a regular expression.
+   * Credits go to [this SO answer]{@link http://stackoverflow.com/a/5306111}
+   *
+   * @param {String} regex string to escape for use in a regular expression.
+   *
+   * @return {String} String with escaped characters for use in a regular
+   * expression.
+   * @function escapeRegularExpression
+   */
+  function escapeRegularExpression(regex) {
+    return regex.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+  }
+
+  /**
+   *
+   * Clean a string in HTML formatted strings that get created with the
+   * namespace tag in some browsers and not in others. Intended to facilitate
+   * testing.
+   *
+   * @param {String} htmlString string to remove namespace from.
+   *
+   * @return {String} String without namespace.
+   * @function cleanHTML
+   */
+  function cleanHTML(htmlString) {
+    return htmlString.replace(' xmlns="http://www.w3.org/1999/xhtml"', '');
+  }
+
+  return {'truncateLevel': truncateLevel, 'naturalSort': naturalSort,
+          'convertXMLToString': convertXMLToString,
+          'escapeRegularExpression': escapeRegularExpression,
+          'cleanHTML': cleanHTML, 'splitNumericValues': splitNumericValues};
+});
diff --git a/emperor/support_files/js/view-controller.js b/emperor/support_files/js/view-controller.js
new file mode 100644
index 0000000..80193f5
--- /dev/null
+++ b/emperor/support_files/js/view-controller.js
@@ -0,0 +1,327 @@
+define([
+    'jquery',
+    'underscore',
+    'view',
+    'slickgrid',
+    'chosen',
+    'abcviewcontroller'
+], function($, _, DecompositionView, SlickGrid, Chosen, abc) {
+  EmperorViewControllerABC = abc.EmperorViewControllerABC;
+
+  /**
+   *
+   * @class EmperorViewController
+   *
+   * Base class for view controllers that use a dictionary of decomposition
+   * views, but that are not controlled by a metadata category, for those
+   * cases, see `EmperorAttributeABC`.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {String} title title of the tab.
+   * @param {String} description helper description.
+   * @param {Object} decompViewDict This is object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {EmperorViewController} Returns an instance of the
+   * EmperorViewController class.
+   * @constructs EmperorViewController
+   * @extends EmperorViewControllerABC
+   *
+   */
+  function EmperorViewController(container, title, description,
+                                 decompViewDict) {
+    EmperorViewControllerABC.call(this, container, title, description);
+    if (decompViewDict === undefined) {
+      throw Error('The decomposition view dictionary cannot be undefined');
+    }
+    for (var dv in decompViewDict) {
+      if (!dv instanceof DecompositionView) {
+        throw Error('The decomposition view dictionary ' +
+            'can only have decomposition views');
+      }
+    }
+    if (_.size(decompViewDict) <= 0) {
+      throw Error('The decomposition view dictionary cannot be empty');
+    }
+    // Picks the first key in the dictionary as the active key
+    /**
+     * @type {String}
+     * This is the key of the active decomposition view.
+     */
+    this.activeViewKey = Object.keys(decompViewDict)[0];
+
+    /**
+     * @type {Object}
+     * This is object is keyed by unique identifiers and the values are
+     * DecompositionView objects referring to a set of objects presented on
+     * screen. This dictionary will usually be shared by all the tabs in the
+     * application. This argument is passed by reference.
+     */
+    this.decompViewDict = decompViewDict;
+
+    return this;
+  }
+  EmperorViewController.prototype = Object.create(
+      EmperorViewControllerABC.prototype);
+  EmperorViewController.prototype.constructor = EmperorViewControllerABC;
+
+  /**
+   * Retrieves the name of the currently active decomposition view.
+   *
+   * @return {String} A key corresponding to the active decomposition view.
+   */
+  EmperorViewController.prototype.getActiveDecompViewKey = function() {
+    return this.activeViewKey;
+  };
+
+  /**
+   * Changes the currently active decomposition view.
+   *
+   * @param {String} k Key corresponding to active decomposition view.
+   * @throws {Error} The key must exist, otherwise an exception will be thrown.
+   */
+  EmperorViewController.prototype.setActiveDecompViewKey = function(k) {
+    if (this.decompViewDict[k] === undefined) {
+      throw new Error('This key does not exist, "' + k + '" in the ' +
+                      'the decompViewDict.');
+    }
+    this.activeViewKey = k;
+  };
+
+  /**
+   * Retrieves the currently active decomposition view.
+   *
+   * @return {DecompositionView} The currently active decomposition view.
+   */
+  EmperorViewController.prototype.getActiveView = function() {
+    return this.decompViewDict[this.getActiveDecompViewKey()];
+  };
+
+  /**
+   *
+   * @class EmperorAttributeABC
+   *
+   * Initializes an abstract tab for attributes i.e. shape, color, size, etc.
+   * This has to be contained in a DOM object and will use the full size of
+   * that container.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {String} title title of the tab.
+   * @param {String} description helper description.
+   * @param {Object} decompViewDict This is object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   * @param {Object} options This is a dictionary of options used to build
+   * the view controller. Used to set attributes of the slick grid and the
+   * metadata category drop down. At the moment the constructor only expects
+   * the following attributes:
+   *  - categorySelectionCallback: a function object that's called when a new
+   *  metadata category is selected in the dropdown living in the header.
+   *  See [change]{@link https://api.jquery.com/change/}.
+   *  - valueUpdatedCallback: a function object that's called when a metadata
+   *  visualization attribute is modified (i.e. a change of color).
+   *  See [onCellChange]{@link
+   *  https://github.com/mleibman/SlickGrid/wiki/Grid-Events}.
+   *  - slickGridColumn: a dictionary specifying options to be passed into the
+   *  slickGrid. For instance, the ColorFormatter and the ColorEditor would be
+   *  passed here.  For more information, refer to the Slick Grid
+   *  documentation.
+   *
+   * @return {EmperorAttributeABC} Returns an instance of the
+   * EmperorAttributeABC class.
+   * @constructs EmperorAttributeABC
+   * @extends EmperorViewController
+   *
+   */
+  function EmperorAttributeABC(container, title, description,
+      decompViewDict, options) {
+    EmperorViewController.call(this, container, title, description,
+                               decompViewDict);
+
+    /**
+     * @type {Node}
+     * jQuery element for the div containing the slickgrid of sample information
+     */
+    this.$gridDiv = $('<div name="emperor-grid-div"></div>');
+    this.$gridDiv.css('margin', '0 auto');
+    this.$gridDiv.css('width', '100%');
+    this.$gridDiv.css('height', '100%');
+    this.$body.append(this.$gridDiv);
+    /**
+     * @type {String}
+     * Metadata column name.
+     */
+    this.metadataField = null;
+
+    var dm = decompViewDict[this.activeViewKey].decomp;
+    var scope = this;
+
+    // http://stackoverflow.com/a/6602002
+    this.$select = $('<select>');
+    _.each(dm.md_headers, function(header) {
+      scope.$select.append($('<option>').attr('value', header).text(header));
+    });
+    this.$header.append(this.$select);
+
+    // there's a few attributes we can only set on "ready" so list them up here
+    $(function() {
+      // setup the slick grid
+      scope._buildGrid(options);
+
+      // setup chosen
+      scope.$select.chosen({width: '100%', search_contains: true});
+
+      // only subclasses will provide this callback
+      if (options.categorySelectionCallback !== undefined) {
+        scope.$select.chosen().change(options.categorySelectionCallback);
+
+        // now that we have the chosen selector and the table fire a callback
+        // to initialize the data grid
+        options.categorySelectionCallback(
+          null, {selected: scope.$select.val()});
+      }
+
+    });
+
+    return this;
+  }
+  EmperorAttributeABC.prototype = Object.create(
+    EmperorViewController.prototype);
+  EmperorAttributeABC.prototype.constructor = EmperorViewController;
+
+  /**
+   * Changes the metadata column name to control.
+   *
+   * @param {String} m Metadata column name to control.
+   */
+  EmperorAttributeABC.prototype.setMetadataField = function(m) {
+    // FIXME: this should be validated against decompViewDict i.e. we should be
+    // verifying that the metadata field indeed exists in the decomposition
+    // model
+    this.metadataField = m;
+  };
+
+  /**
+   * Retrieves the underlying data in the slick grid
+   * @return {Array} Returns an array of objects
+   * displayed by the body grid.
+   */
+  EmperorAttributeABC.prototype.getSlickGridDataset = function() {
+    return this.bodyGrid.getData();
+  };
+
+  /**
+   * Changes the underlying data in the slick grid
+   *
+   * @param {Array} data data.
+   */
+  EmperorAttributeABC.prototype.setSlickGridDataset = function(data) {
+    // Re-render
+    this.bodyGrid.setData(data);
+    this.bodyGrid.invalidate();
+    this.bodyGrid.render();
+  };
+
+  /**
+   * Method in charge of initializing the SlickGrid object
+   *
+   * @param {Object} [options] additional options to initialize the slick grid
+   * of this object.
+   * @private
+   *
+   */
+  EmperorAttributeABC.prototype._buildGrid = function(options) {
+    var columns = [{id: 'field1', name: '', field: 'category'}];
+    var gridOptions = {editable: true, enableAddRow: false,
+      enableCellNavigation: true, forceFitColumns: true,
+      enableColumnReorder: false, autoEdit: true};
+
+    // If there's a custom slickgrid column then add it to the object
+    if (options.slickGridColumn !== undefined) {
+      columns.unshift(options.slickGridColumn);
+    }
+
+    /**
+     * @type {Slick.Grid}
+     * Container that lists the metadata categories described under the
+     * `metadataField` column and the attribute that can be modified.
+     */
+    this.bodyGrid = new Slick.Grid(this.$gridDiv, [], columns, gridOptions);
+
+    // hide the header row of the grid
+    // http://stackoverflow.com/a/29827664/379593
+    $(this.$body).find('.slick-header').css('display', 'none');
+
+    // subscribe to events when a cell is changed
+    this.bodyGrid.onCellChange.subscribe(options.valueUpdatedCallback);
+  };
+
+  /**
+   * Resizes the container and the individual elements.
+   *
+   * Note, the consumer of this class, likely the main controller should call
+   * the resize function any time a resizing event happens.
+   *
+   * @param {Float} width the container width.
+   * @param {Float} height the container height.
+   */
+  EmperorAttributeABC.prototype.resize = function(width, height) {
+    // call super, most of the header and body resizing logic is done there
+    EmperorViewController.prototype.resize.call(this, width, height);
+
+    // the whole code is asynchronous, so there may be situations where
+    // bodyGrid doesn't exist yet, so check before trying to modify the object
+    if (this.bodyGrid !== undefined) {
+      // make the columns fit the available space whenever the window resizes
+      // http://stackoverflow.com/a/29835739
+      this.bodyGrid.setColumns(this.bodyGrid.getColumns());
+      // Resize the slickgrid canvas for the new body size.
+      this.bodyGrid.resizeCanvas();
+    }
+  };
+
+  /**
+   * Converts the current instance into a JSON object.
+   *
+   * @return {Object} base object ready for JSON conversion.
+   */
+  EmperorAttributeABC.prototype.toJSON = function() {
+    var json = {};
+    json.category = this.$select.val();
+
+    // Convert SlickGrid list of objects to single object
+    var gridData = this.bodyGrid.getData();
+    var jsonData = {};
+    for (var i = 0; i < gridData.length; i++) {
+      jsonData[gridData[i].category] = gridData[i].value;
+    }
+    json.data = jsonData;
+    return json;
+  };
+
+  /**
+   * Decodes JSON string and modifies its own instance variables accordingly.
+   *
+   * @param {Object} json Parsed JSON string representation of self.
+   *
+   */
+  EmperorAttributeABC.prototype.fromJSON = function(json) {
+    this.$select.val(json.category);
+    this.$select.trigger('chosen:updated');
+
+    // fetch and set the SlickGrid-formatted data
+    var k = this.getActiveDecompViewKey();
+    var data = this.decompViewDict[k].setCategory(
+      json.data, this.setPlottableAttributes, json.category);
+    this.setSlickGridDataset(data);
+    // set all to needsUpdate
+    this.decompViewDict[k].needsUpdate = true;
+  };
+
+  return {'EmperorViewControllerABC': EmperorViewControllerABC,
+          'EmperorViewController': EmperorViewController,
+          'EmperorAttributeABC': EmperorAttributeABC};
+});
diff --git a/emperor/support_files/js/view.js b/emperor/support_files/js/view.js
new file mode 100644
index 0000000..a38d4c6
--- /dev/null
+++ b/emperor/support_files/js/view.js
@@ -0,0 +1,285 @@
+define([
+    'jquery',
+    'underscore',
+    'three',
+    'shapes'
+], function($, _, THREE, shapes) {
+/**
+ *
+ * @class DecompositionView
+ *
+ * Contains all the information on how the model is being presented to the
+ * user.
+ *
+ * @param {DecompositionModel} decomp a DecompositionModel object that will be
+ * represented on screen.
+ *
+ * @return {DecompositionView}
+ * @constructs DecompositionView
+ *
+ */
+function DecompositionView(decomp) {
+  /**
+   * The decomposition model that the view represents.
+   * @type {DecompositionModel}
+   */
+  this.decomp = decomp;
+  /**
+   * Number of samples represented in the view.
+   * @type {integer}
+   */
+  this.count = decomp.length;
+  /**
+   * Number of visible samples.
+   * @type {integer}
+   */
+  this.visibleCount = this.count;
+  /**
+   * Top visible dimensions
+   * @type {integer[]}
+   * @default [0, 1, 2]
+   */
+  this.visibleDimensions = [0, 1, 2]; // We default to the first three PCs
+  /**
+   * Orientation of the axes, `-1` means the axis is flipped, `1` means the
+   * axis is not flipped.
+   * @type {integer[]}
+   * @default [1, 1, 1]
+   */
+  this.axesOrientation = [1, 1, 1];
+  /**
+   * Axes color.
+   * @type {integer}
+   * @default 0xFFFFFF (white)
+   */
+  this.axesColor = 0xFFFFFF;
+  /**
+   * Background color.
+   * @type {integer}
+   * @default 0x000000 (black)
+   */
+  this.backgroundColor = 0x000000;
+  /**
+   * Tube objects on screen (used for animations)
+   * @type {THREE.Mesh[]}
+   */
+  this.tubes = [];
+  /**
+   * Array of THREE.Mesh objects on screen (represent samples).
+   * @type {THREE.Mesh[]}
+   */
+  this.markers = [];
+  /**
+   * Array of line objects shown on screen (used for procustes and vector
+   * plots).
+   * @type {THREE.Line[]}
+   */
+  this.lines = [];
+
+  // setup this.markers and this.lines
+  this._initBaseView();
+
+  /**
+   * True when changes have occured that require re-rendering of the canvas
+   * @type {boolean}
+   */
+  this.needsUpdate = true;
+}
+
+/**
+ *
+ * Helper method to initialize the base THREE.js objects.
+ * @private
+ *
+ */
+DecompositionView.prototype._initBaseView = function() {
+  var mesh, x = this.visibleDimensions[0], y = this.visibleDimensions[1],
+      z = this.visibleDimensions[2];
+  var scope = this;
+
+  // get the correctly sized geometry
+  var geometry = shapes.getGeometry('Sphere', this.decomp.dimensionRanges);
+
+  this.decomp.apply(function(plottable) {
+    mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial());
+    mesh.name = plottable.name;
+
+    mesh.material.color = new THREE.Color(0xff0000);
+    mesh.material.transparent = false;
+    mesh.material.depthWrite = true;
+    mesh.material.opacity = 1;
+    mesh.matrixAutoUpdate = true;
+
+    mesh.position.set(plottable.coordinates[x], plottable.coordinates[y],
+                      plottable.coordinates[z]);
+
+    mesh.updateMatrix();
+
+    scope.markers.push(mesh);
+  });
+
+  // apply but to the adjacency list NOT IMPLEMENTED
+  // this.decomp.applyAJ( ... ); Blame Jamie and Jose - baby steps buddy...
+
+};
+
+/**
+ *
+ * Change the visible coordinates
+ *
+ * @param {integer[]} newDims An Array of integers in which each integer is the
+ * index to the principal coordinate to show
+ *
+ */
+DecompositionView.prototype.changeVisibleDimensions = function(newDims) {
+  if (newDims.length !== 3) {
+    throw new Error('Only three dimensions can be shown at the same time');
+  }
+
+  // one by one, find and update the dimensions that are changing
+  for (var i = 0; i < 3; i++) {
+    if (this.visibleDimensions[i] !== newDims[i]) {
+      // index represents the global position of the dimension
+      var index = this.visibleDimensions[i],
+          orientation = this.axesOrientation[i];
+
+      // 1.- Correct the limits of the ranges for the dimension that we are
+      // moving out of the scene i.e. the old dimension
+      if (this.axesOrientation[i] === -1) {
+        var max = this.decomp.dimensionRanges.max[index];
+        var min = this.decomp.dimensionRanges.min[index];
+        this.decomp.dimensionRanges.max[index] = min * (-1);
+        this.decomp.dimensionRanges.min[index] = max * (-1);
+      }
+
+      // 2.- Set the orientation of the new dimension to be 1
+      this.axesOrientation[i] = 1;
+
+      // 3.- Update the visible dimensions to include the new value
+      this.visibleDimensions[i] = newDims[i];
+    }
+  }
+
+  var x = this.visibleDimensions[0], y = this.visibleDimensions[1],
+      z = this.visibleDimensions[2], scope = this;
+
+  this.decomp.apply(function(plottable) {
+    mesh = scope.markers[plottable.idx];
+
+    // always use the original data plus the axis orientation
+    mesh.position.set(plottable.coordinates[x] * scope.axesOrientation[0],
+                      plottable.coordinates[y] * scope.axesOrientation[1],
+                      plottable.coordinates[z] * scope.axesOrientation[2]);
+    mesh.updateMatrix();
+  });
+
+  this.needsUpdate = true;
+};
+
+/**
+ *
+ * Reorient one of the visible dimensions.
+ *
+ * @param {integer} index The index of the dimension to re-orient, if this
+ * dimension is not visible i.e. not in `this.visibleDimensions`, then the
+ * method will return right away.
+ *
+ */
+DecompositionView.prototype.flipVisibleDimension = function(index) {
+  var pos, scope = this, newMin, newMax;
+
+  // the index in the visible dimensions
+  var localIndex = this.visibleDimensions.indexOf(index);
+
+  if (localIndex !== -1) {
+    var x = this.visibleDimensions[0], y = this.visibleDimensions[1],
+        z = this.visibleDimensions[2];
+
+    // update the ranges for this decomposition
+    var max = this.decomp.dimensionRanges.max[index];
+    var min = this.decomp.dimensionRanges.min[index];
+    this.decomp.dimensionRanges.max[index] = min * (-1);
+    this.decomp.dimensionRanges.min[index] = max * (-1);
+
+    // and update the state of the orientation
+    this.axesOrientation[localIndex] *= -1;
+
+    this.decomp.apply(function(plottable) {
+      mesh = scope.markers[plottable.idx];
+      pos = mesh.position.toArray();
+
+      // always use the original data plus the axis orientation
+      mesh.position.set(plottable.coordinates[x] * scope.axesOrientation[0],
+                        plottable.coordinates[y] * scope.axesOrientation[1],
+                        plottable.coordinates[z] * scope.axesOrientation[2]);
+      mesh.updateMatrix();
+    });
+
+    this.needsUpdate = true;
+  }
+};
+
+/**
+ * Change the plottables attributes based on the metadata category using the
+ * provided setPlottableAttributes function
+ *
+ * @param {object} attributes Key:value pairs of elements and values to change
+ * in plottables.
+ * @param {function} setPlottableAttributes Helper function to change the
+ * values of plottables, in general this should be implemented in the
+ * controller but it can be nullable if not needed. setPlottableAttributes
+ * should receive: the scope where the plottables exist, the value to be
+ * applied to the plottables and the plotables to change. For more info
+ * see ColorViewController.setPlottableAttribute
+ * @see ColorViewController.setPlottableAttribute
+ * @param {string} category The category/column in the mapping file
+ *
+ * @return {object[]} Array of objects to be consumed by Slick grid.
+ *
+ */
+DecompositionView.prototype.setCategory = function(attributes,
+                                                   setPlottableAttributes,
+                                                   category) {
+  var scope = this, dataView = [], plottables;
+
+  _.each(attributes, function(value, key) {
+    /*
+     *
+     * WARNING: This is mixing attributes of the view with the model ...
+     * it's a bit of a gray area though.
+     *
+     **/
+    plottables = scope.decomp.getPlottablesByMetadataCategoryValue(category,
+                                                                   key);
+    if (setPlottableAttributes !== null) {
+      setPlottableAttributes(scope, value, plottables);
+    }
+
+    dataView.push({category: key, value: value, plottables: plottables});
+  });
+  this.needsUpdate = true;
+
+  return dataView;
+};
+
+/**
+ *
+ * Change the color for a set of plottables.
+ *
+ * @param {integer} color An RGB color in hexadecimal format.
+ * @param {Plottable[]} group Array of Plottables that will change in color.
+ *
+ */
+DecompositionView.prototype.setGroupColor = function(color, group) {
+  var idx;
+  var scope = this;
+
+  _.each(group, function(element) {
+    idx = element.idx;
+    scope.markers[idx].material.color = new THREE.Color(color);
+  });
+};
+this.needsUpdate = true;
+
+  return DecompositionView;
+});
diff --git a/emperor/support_files/js/visibility-controller.js b/emperor/support_files/js/visibility-controller.js
new file mode 100644
index 0000000..5ae4ad2
--- /dev/null
+++ b/emperor/support_files/js/visibility-controller.js
@@ -0,0 +1,96 @@
+define([
+    'jquery',
+    'underscore',
+    'viewcontroller',
+    'chroma',
+    'slickformatters',
+    'slickeditors'
+], function($, _, ViewControllers, chroma, slickformatters, slickeditors) {
+
+  // we only use the base attribute class, no need to get the base class
+  /** @private */
+  var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
+  /**
+   * @class VisibilityController
+   *
+   * Manipulates and displays the visibility of objects on screen.
+   *
+   * @param {Node} container Container node to create the controller in.
+   * @param {Object} decompViewDict This object is keyed by unique
+   * identifiers and the values are DecompositionView objects referring to a
+   * set of objects presented on screen. This dictionary will usually be shared
+   * by all the tabs in the application. This argument is passed by reference.
+   *
+   * @return {VisibilityController} An instance of VisibilityController
+   * @constructs VisibilityController
+   * @extends EmperorAttributeABC
+   */
+  function VisibilityController(container, decompViewDict) {
+    var helpmenu = 'Change the visibility of the attributes on the plot, ' +
+                   'such as spheres, vectors and ellipsoids.';
+    var title = 'Visibility';
+
+    // Constant for width in slick-grid
+    var SLICK_WIDTH = 25, scope = this;
+
+    // Build the options dictionary
+    var options = {'valueUpdatedCallback': function(e, args) {
+      var visible = args.item.value;
+      var group = args.item.plottables;
+      var element = scope.decompViewDict[scope.getActiveDecompViewKey()];
+      scope.setPlottableAttributes(element, visible, group);
+    },
+      'categorySelectionCallback': function(evt, params) {
+        var category = scope.$select.val();
+
+        var k = scope.getActiveDecompViewKey();
+        var decompViewDict = scope.decompViewDict[k];
+
+        // getting all unique values per categories
+        var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
+          category);
+        // getting color for each uniqueVals
+        var attributes = {};
+        _.each(uniqueVals, function(value) {
+          attributes[value] = true;
+        });
+        // fetch the slickgrid-formatted data
+        var data = decompViewDict.setCategory(
+          attributes, scope.setPlottableAttributes, category);
+
+        scope.setSlickGridDataset(data);
+      },
+      'slickGridColumn': {id: 'title', name: '', field: 'value',
+        sortable: false, maxWidth: SLICK_WIDTH,
+        minWidth: SLICK_WIDTH,
+        autoEdit: true,
+        formatter: Slick.Formatters.Checkmark,
+        editor: Slick.Editors.Checkbox}};
+
+    EmperorAttributeABC.call(this, container, title, helpmenu,
+        decompViewDict, options);
+    return this;
+  }
+  VisibilityController.prototype = Object.create(EmperorAttributeABC.prototype);
+  VisibilityController.prototype.constructor = EmperorAttributeABC;
+
+  /**
+   * Helper function to set the visibility of plottable
+   *
+   * @param {Object} scope the scope where the plottables exist
+   * @param {boolean} visible Visibility of the plottables
+   * @param {Object[]} group Array of objects that should be changed in scope
+   */
+  VisibilityController.prototype.setPlottableAttributes =
+      function(scope, visible, group) {
+    var idx;
+
+    _.each(group, function(element) {
+      idx = element.idx;
+      scope.markers[idx].visible = visible;
+    });
+    scope.needsUpdate = true;
+  };
+
+  return VisibilityController;
+});
diff --git a/emperor/support_files/templates/jupyter-template.html b/emperor/support_files/templates/jupyter-template.html
new file mode 100644
index 0000000..0f942e9
--- /dev/null
+++ b/emperor/support_files/templates/jupyter-template.html
@@ -0,0 +1,3 @@
+{# Load templates dynamically, so we can figure out the path on the fly #}
+{% include style_template_path %}
+{% include logic_template_path %}
diff --git a/emperor/support_files/templates/logic-template.html b/emperor/support_files/templates/logic-template.html
new file mode 100644
index 0000000..0e5eacb
--- /dev/null
+++ b/emperor/support_files/templates/logic-template.html
@@ -0,0 +1,132 @@
+<div id='{{ plot_id }}' style="position: relative; width:100%; height:500px;">
+  <div class='loading' style="position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px"><img src='{{ base_url }}/img/emperor.png' alt='Emperor resources missing. Expected them to be found in {{ base_url }}'></div>
+</div>
+</div>
+
+<script type="text/javascript">
+requirejs.config({
+// the left side is the module name, and the right side is the path
+// relative to the baseUrl attribute, do NOT include the .js extension
+'paths': {
+  /* jQuery */
+  'jquery': '{{ base_url }}/vendor/js/jquery-2.1.4.min',
+  'jqueryui': '{{ base_url }}/vendor/js/jquery-ui.min',
+  'jquery_drag': '{{ base_url }}/vendor/js/jquery.event.drag-2.2.min',
+
+  /* jQuery plugins */
+  'chosen': '{{ base_url }}/vendor/js/chosen.jquery.min',
+  'spectrum': '{{ base_url }}/vendor/js/spectrum.min',
+  'position': '{{ base_url }}/vendor/js/jquery.ui.position.min',
+  'contextmenu': '{{ base_url }}/vendor/js/jquery.contextMenu.min',
+
+  /* other libraries */
+  'underscore': '{{ base_url }}/vendor/js/underscore-min',
+  'chroma': '{{ base_url }}/vendor/js/chroma.min',
+  'filesaver': '{{ base_url }}/vendor/js/FileSaver.min',
+  'blob': '{{ base_url }}/vendor/js/Blob',
+  'd3': '{{ base_url }}/vendor/js/d3.min',
+
+  /* THREE.js and plugins */
+  'three': '{{ base_url }}/vendor/js/three.min',
+  'orbitcontrols': '{{ base_url }}/vendor/js/three.js-plugins/OrbitControls',
+  'projector': '{{ base_url }}/vendor/js/three.js-plugins/Projector',
+  'svgrenderer': '{{ base_url }}/vendor/js/three.js-plugins/SVGRenderer',
+
+  /* SlickGrid */
+  'slickcore': '{{ base_url }}/vendor/js/slick.core.min',
+  'slickgrid': '{{ base_url }}/vendor/js/slick.grid.min',
+  'slickformatters': '{{ base_url }}/vendor/js/slick.editors.min',
+  'slickeditors': '{{ base_url }}/vendor/js/slick.formatters.min',
+
+  /* Emperor's objects */
+  'util': '{{ base_url }}/js/util',
+  'model': '{{ base_url }}/js/model',
+  'view': '{{ base_url }}/js/view',
+  'controller': '{{ base_url }}/js/controller',
+  'draw': '{{ base_url }}/js/draw',
+  'scene3d': '{{ base_url }}/js/sceneplotview3d',
+  'abcviewcontroller': '{{ base_url }}/js/abc-view-controller',
+  'viewcontroller': '{{ base_url }}/js/view-controller',
+  'colorviewcontroller': '{{ base_url }}/js/color-view-controller',
+  'visibilitycontroller': '{{ base_url }}/js/visibility-controller',
+  'scaleviewcontroller': '{{ base_url }}/js/scale-view-controller',
+  'shapecontroller': '{{ base_url }}/js/shape-controller',
+  'axescontroller': '{{ base_url }}/js/axes-controller',
+  'shape-editor': '{{ base_url }}/js/shape-editor',
+  'color-editor': '{{ base_url }}/js/color-editor',
+  'scale-editor': '{{ base_url }}/js/scale-editor',
+  'shapes': '{{ base_url }}/js/shapes'
+},
+/*
+   Libraries that are not AMD compatible need shim to declare their
+   dependencies.
+ */
+'shim': {
+  'jquery_drag': {
+    'deps': ['jquery', 'jqueryui']
+  },
+  'chosen': {
+    'deps': ['jquery'],
+    'exports': 'jQuery.fn.chosen'
+  },
+  'contextmenu' : {
+    'deps': ['jquery', 'jqueryui', 'position']
+  },
+  'filesaver' : {
+    'deps': ['blob']
+  },
+  'orbitcontrols': {
+    'deps': ['three']
+  },
+  'projector': {
+    'deps': ['three']
+  },
+  'svgrenderer': {
+    'deps': ['orbitcontrols', 'projector']
+  },
+'slickcore': ['jqueryui'],
+'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
+              'slickeditors']
+}
+});
+
+requirejs(
+["jquery", "model", "controller"],
+function($, model, EmperorController) {
+  var DecompositionModel = model.DecompositionModel;
+
+  var div = $('#{{ plot_id }}');
+
+  var ids = {{ coords_ids }};
+  var coords = {{ coords }};
+  var pct_var = {{ pct_var | map('float') | list }};
+  var md_headers = {{ md_headers}};
+  var metadata = {{  metadata }};
+  var axesNames = {{ axes_names }};
+
+  var dm, ec;
+
+  function init() {
+    // Initialize the DecompositionModel
+    dm = new DecompositionModel(name, ids, coords, pct_var,
+                                md_headers, metadata, axesNames);
+    // Initialize the EmperorController
+    ec = new EmperorController(dm, '{{ plot_id }}');
+  }
+
+  function animate() {
+    requestAnimationFrame(animate);
+    ec.render();
+  }
+  $(window).resize(function() {
+    ec.resize(div.innerWidth(), div.innerHeight());
+  });
+
+  $(function(){
+    init();
+    animate();
+
+  });
+
+}); // END REQUIRE.JS block
+</script>
diff --git a/emperor/support_files/templates/standalone-template.html b/emperor/support_files/templates/standalone-template.html
new file mode 100644
index 0000000..c3d4a97
--- /dev/null
+++ b/emperor/support_files/templates/standalone-template.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title>Emperor</title>
+    <!-- core dependencies that are otherwise included via the jupyter notebook -->
+    <script src="{{ base_url }}/vendor/js/require-2.1.22.min.js"></script>
+    <script src="{{ base_url }}/vendor/js/jquery-2.1.4.min.js"></script>
+    <meta charset="utf-8">
+
+    {% include style_template_path %}
+
+    <style>
+      #{{ plot_id }} {
+        height:100vh !important;
+        padding: 0px !important;
+      }
+      body {
+        margin: 0;
+        padding: 0;
+        border: 0;
+        outline: 0;
+      }
+    </style>
+  </head>
+  <body>
+    {% include logic_template_path %}
+  </body>
+</html>
diff --git a/emperor/support_files/templates/style-template.html b/emperor/support_files/templates/style-template.html
new file mode 100644
index 0000000..67452f0
--- /dev/null
+++ b/emperor/support_files/templates/style-template.html
@@ -0,0 +1,15 @@
+<script type="text/javascript">
+{% raw %}
+if ($("#emperor-css").length == 0){{
+    $("head").append([
+{% endraw %}
+        '<link id="emperor-css" rel="stylesheet" type="text/css" href="{{ base_url }}/css/emperor.css">',
+        '<link rel="stylesheet" type="text/css" href="{{ base_url }}/vendor/css/jquery-ui.min.css">',
+        '<link rel="stylesheet" type="text/css" href="{{ base_url }}/vendor/css/slick.grid.min.css">',
+        '<link rel="stylesheet" type="text/css" href="{{ base_url }}/vendor/css/spectrum.min.css">',
+        '<link rel="stylesheet" type="text/css" href="{{ base_url }}/vendor/css/chosen.min.css">',
+        '<link rel="stylesheet" type="text/css" href="{{ base_url }}/vendor/css/jquery.contextMenu.min.css">'
+    ]);
+}}
+</script>
+
diff --git a/emperor/support_files/vendor/css/chosen-sprite.png b/emperor/support_files/vendor/css/chosen-sprite.png
new file mode 100644
index 0000000..c57da70
Binary files /dev/null and b/emperor/support_files/vendor/css/chosen-sprite.png differ
diff --git a/emperor/support_files/vendor/css/chosen-sprite at 2x.png b/emperor/support_files/vendor/css/chosen-sprite at 2x.png
new file mode 100644
index 0000000..6b50545
Binary files /dev/null and b/emperor/support_files/vendor/css/chosen-sprite at 2x.png differ
diff --git a/emperor/support_files/vendor/css/chosen.min.css b/emperor/support_files/vendor/css/chosen.min.css
new file mode 100644
index 0000000..5ca6159
--- /dev/null
+++ b/emperor/support_files/vendor/css/chosen.min.css
@@ -0,0 +1,3 @@
+/* Chosen v1.4.2 | (c) 2011-2015 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */
+
+.chosen-container{position:relative;display:inline-block;vertical-align:middle;font-size:13px;zoom:1;*display:inline;-webkit-user-select:none;-moz-user-select:none;user-select:none}.chosen-container *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.chosen-container .chosen-drop{position:absolute;top:100%;left:-9999px;z-index:1010;width:100%;border:1px solid #aaa;border-top:0;background:#fff;box-shadow:0 4px 5px rgba(0,0,0,.15)}.chosen-container.chosen-with [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/css/font/context-menu-icons.eot b/emperor/support_files/vendor/css/font/context-menu-icons.eot
new file mode 100644
index 0000000..8113d37
Binary files /dev/null and b/emperor/support_files/vendor/css/font/context-menu-icons.eot differ
diff --git a/emperor/support_files/vendor/css/font/context-menu-icons.ttf b/emperor/support_files/vendor/css/font/context-menu-icons.ttf
new file mode 100644
index 0000000..cbc465d
Binary files /dev/null and b/emperor/support_files/vendor/css/font/context-menu-icons.ttf differ
diff --git a/emperor/support_files/vendor/css/font/context-menu-icons.woff b/emperor/support_files/vendor/css/font/context-menu-icons.woff
new file mode 100644
index 0000000..010b26b
Binary files /dev/null and b/emperor/support_files/vendor/css/font/context-menu-icons.woff differ
diff --git a/emperor/support_files/vendor/css/font/context-menu-icons.woff2 b/emperor/support_files/vendor/css/font/context-menu-icons.woff2
new file mode 100644
index 0000000..4246a5a
Binary files /dev/null and b/emperor/support_files/vendor/css/font/context-menu-icons.woff2 differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_glass_55_fbf9ee_1x400.png b/emperor/support_files/vendor/css/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..c4d8fef
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_glass_55_fbf9ee_1x400.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_glass_65_ffffff_1x400.png b/emperor/support_files/vendor/css/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..74aebb1
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_glass_65_ffffff_1x400.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_glass_75_dadada_1x400.png b/emperor/support_files/vendor/css/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..b382a85
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_glass_75_dadada_1x400.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_glass_75_e6e6e6_1x400.png b/emperor/support_files/vendor/css/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..aa3f24f
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_glass_75_e6e6e6_1x400.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_glass_95_fef1ec_1x400.png b/emperor/support_files/vendor/css/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..1d94314
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_glass_95_fef1ec_1x400.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..bc5e961
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
new file mode 100644
index 0000000..367be20
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-icons_222222_256x240.png b/emperor/support_files/vendor/css/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..e9c8e16
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-icons_222222_256x240.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-icons_2e83ff_256x240.png b/emperor/support_files/vendor/css/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..f2bf838
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-icons_2e83ff_256x240.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-icons_454545_256x240.png b/emperor/support_files/vendor/css/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..d6169e8
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-icons_454545_256x240.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-icons_888888_256x240.png b/emperor/support_files/vendor/css/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..d3e6e02
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-icons_888888_256x240.png differ
diff --git a/emperor/support_files/vendor/css/images/ui-icons_cd0a0a_256x240.png b/emperor/support_files/vendor/css/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..4937018
Binary files /dev/null and b/emperor/support_files/vendor/css/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/emperor/support_files/vendor/css/jquery-ui.min.css b/emperor/support_files/vendor/css/jquery-ui.min.css
new file mode 100644
index 0000000..1b246a9
--- /dev/null
+++ b/emperor/support_files/vendor/css/jquery-ui.min.css
@@ -0,0 +1,7 @@
+/*! jQuery UI - v1.11.4 - 2016-01-06
+* http://jqueryui.com
+* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, menu.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDe [...]
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;heig [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/css/jquery.contextMenu.min.css b/emperor/support_files/vendor/css/jquery.contextMenu.min.css
new file mode 100644
index 0000000..ed5bd10
--- /dev/null
+++ b/emperor/support_files/vendor/css/jquery.contextMenu.min.css
@@ -0,0 +1,15 @@
+ at charset "UTF-8";/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: v2.1.1
+ *
+ * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://swisnl.github.io/jQuery-contextMenu/
+ *
+ * Copyright (c) 2011-2016 SWIS BV and contributors
+ *
+ * Licensed under
+ *   MIT License http://www.opensource.org/licenses/mit-license
+ *
+ * Date: @DATE
+ */.context-menu-icon.context-menu-icon--fa::before,.context-menu-icon::before{font-style:normal;font-weight:400;font-size:1em;left:0;line-height:1;text-align:center;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:2em;position:absolute;top:50%;transform:translateY(-50%)}@font-face{font-family:context-menu-icons;src:url(font/context-menu-icons.eot?3hbbg);src:url(font/context-menu-icons.eot?3hbbg#iefix) format("embedded-opentype"),url(font/context-menu-icons.woff [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/css/slick.grid.min.css b/emperor/support_files/vendor/css/slick.grid.min.css
new file mode 100644
index 0000000..02bf744
--- /dev/null
+++ b/emperor/support_files/vendor/css/slick.grid.min.css
@@ -0,0 +1 @@
+.slick-header.ui-state-default,.slick-headerrow.ui-state-default{width:100%;overflow:hidden;border-left:0!important}.slick-header-columns,.slick-headerrow-columns{position:relative;white-space:nowrap;cursor:default;overflow:hidden}.slick-header-column.ui-state-default{position:relative;display:inline-block;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;height:16px;line-height:16px;margin:0;padding:4px;border-right:1px solid silver;border-left:0!important;border-top:0!im [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/css/spectrum.min.css b/emperor/support_files/vendor/css/spectrum.min.css
new file mode 100644
index 0000000..83eea58
--- /dev/null
+++ b/emperor/support_files/vendor/css/spectrum.min.css
@@ -0,0 +1 @@
+.sp-container{position:absolute;top:0;left:0;display:inline-block;z-index:9999994;overflow:hidden}.sp-container.sp-flat,.sp-top{position:relative}.sp-container,.sp-container *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.sp-top{width:100%;display:inline-block}.sp-alpha-handle,.sp-color,.sp-dragger,.sp-hue,.sp-sat,.sp-slider,.sp-top-inner,.sp-val{position:absolute}.sp-top-inner{top:0;left:0;bottom:0;right:0}.sp-color{top:0;left:0;bottom:0;right:20%}.s [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/Blob.js b/emperor/support_files/vendor/js/Blob.js
new file mode 100644
index 0000000..a567284
--- /dev/null
+++ b/emperor/support_files/vendor/js/Blob.js
@@ -0,0 +1,16 @@
+/* Blob.js
+ * A Blob implementation.
+ * 2014-07-24
+ *
+ * By Eli Grey, http://eligrey.com
+ * By Devin Samarin, https://github.com/dsamarin
+ * License: MIT
+ *   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
+ */
+
+/*global self, unescape */
+/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
+  plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
+!function(t){"use strict";if(t.URL=t.URL||t.webkitURL,t.Blob&&t.URL)try{return void new Blob}catch(e){}var n=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||function(t){var e=function(t){return Object.prototype.toString.call(t).match(/^\[object\s(.*)\]$/)[1]},n=function(){this.data=[]},o=function(t,e,n){this.data=t,this.size=t.length,this.type=e,this.encoding=n},i=n.prototype,a=o.prototype,r=t.FileReaderSync,c=function(t){this.code=this[this.name=t]},l="NOT_FOUND_ERR SECURITY_ERR A [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/FileSaver.min.js b/emperor/support_files/vendor/js/FileSaver.min.js
new file mode 100644
index 0000000..6268ec9
--- /dev/null
+++ b/emperor/support_files/vendor/js/FileSaver.min.js
@@ -0,0 +1,2 @@
+/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
+var saveAs=saveAs||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=/Version\/[\d\.]+.*Safari/.test(navigator.userAgent),c=e.webkitRequestFileSystem,f=e.requestFileSystem||c||e.mozRequestFileSystem,u=function(t){(e.setImmediate||e.setTimeou [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/chosen.jquery.min.js b/emperor/support_files/vendor/js/chosen.jquery.min.js
new file mode 100644
index 0000000..22e3865
--- /dev/null
+++ b/emperor/support_files/vendor/js/chosen.jquery.min.js
@@ -0,0 +1,2 @@
+/* Chosen v1.4.2 | (c) 2011-2015 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */
+(function(){var a,AbstractChosen,Chosen,SelectParser,b,c={}.hasOwnProperty,d=function(a,b){function d(){this.constructor=a}for(var e in b)c.call(b,e)&&(a[e]=b[e]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};SelectParser=function(){function SelectParser(){this.options_index=0,this.parsed=[]}return SelectParser.prototype.add_node=function(a){return"OPTGROUP"===a.nodeName.toUpperCase()?this.add_group(a):this.add_option(a)},SelectParser.prototype.add_group=fun [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/chroma.min.js b/emperor/support_files/vendor/js/chroma.min.js
new file mode 100644
index 0000000..cad36c1
--- /dev/null
+++ b/emperor/support_files/vendor/js/chroma.min.js
@@ -0,0 +1,33 @@
+/*
+chroma.js - JavaScript library for color conversions
+
+Copyright (c) 2011-2015, Gregor Aisch
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. The name Gregor Aisch may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea,fa,ga,ha,ia,ja,ka,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,wa,xa,ya,za=[].slice;ua=function(){var a,b,c,d,e;for(a={},e="Boolean Number String Function Array Date RegExp Undefined Null".split(" "),d=0,b=e.length;b>d;d++)c=e[d],a["[object "+c+"]"]=c.toLowerCase();return function(b){var c;return c=Object.prototype.toString.call(b),a[c]||"object"}}(),S=function(a [...]
+},k.push(["lab",J])}).call(this);
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/d3.min.js b/emperor/support_files/vendor/js/d3.min.js
new file mode 100644
index 0000000..1664873
--- /dev/null
+++ b/emperor/support_files/vendor/js/d3.min.js
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(argum [...]
+r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r [...]
+return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return [...]
+shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=xa.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,ba),st(ba.s,this.s,this),this.s?this.t+=ba.t:this.s=ba.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var ba=new ft;ao.g [...]
+if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<o;)i=n[u],i.x=a,i.y=c,i.dy=f,a+=i.dx=Math.min(e.x+e.dx-a,f?l(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-a,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<o;)i=n[u],i.x=a,i.y=c,i.dx=f,c+=i.dy=Math.min(e.y+e.dy-c,f?l(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-c,e.x+=f,e.dx-=f}}function u(r){var i=o||a(r),u=i[0];return u.x=u.y=0,u.value?(u.dx=c[0],u.dy=c[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?e:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),l [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/jquery-2.1.4.min.js b/emperor/support_files/vendor/js/jquery-2.1.4.min.js
new file mode 100644
index 0000000..49990d6
--- /dev/null
+++ b/emperor/support_files/vendor/js/jquery-2.1.4.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r= [...]
+return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(functio [...]
+void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c [...]
diff --git a/emperor/support_files/vendor/js/jquery-ui.min.js b/emperor/support_files/vendor/js/jquery-ui.min.js
new file mode 100644
index 0000000..9baf740
--- /dev/null
+++ b/emperor/support_files/vendor/js/jquery-ui.min.js
@@ -0,0 +1,13 @@
+/*! jQuery UI - v1.11.4 - 2016-01-03
+* http://jqueryui.com
+* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake. [...]
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this, [...]
+},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.h [...]
+this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addCla [...]
+},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id");t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpa [...]
+},_destroyDatepicker:function(t){var i,s=e(t),n=e.data(t,"datepicker");s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),v===n&&(v=null))},_enableDatepicker:f [...]
+return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var e=this._focusedElement;e||(e= [...]
+},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class=' [...]
+return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/jquery.contextMenu.min.js b/emperor/support_files/vendor/js/jquery.contextMenu.min.js
new file mode 100644
index 0000000..0bcef8e
--- /dev/null
+++ b/emperor/support_files/vendor/js/jquery.contextMenu.min.js
@@ -0,0 +1,18 @@
+/*!
+ * jQuery contextMenu v2.1.1 - Plugin for simple contextMenu handling
+ *
+ * Version: v2.1.1
+ *
+ * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://swisnl.github.io/jQuery-contextMenu/
+ *
+ * Copyright (c) 2011-2016 SWIS BV and contributors
+ *
+ * Licensed under
+ *   MIT License http://www.opensource.org/licenses/mit-license
+ *   GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ * Date: 2016-04-25T15:38:06.806Z
+ */
+!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){"use strict";function t(e){for(var t,n=e.split(/\s+/),a=[],o=0;t=n[o];o++)t=t.charAt(0).toUpperCase(),a.push(t);return a}function n(t){return t.id&&e('label[for="'+t.id+'"]').val()||t.name}function a(t,o,s){return s||(s=0),o.each(function(){var o,i,c=e(this),r=this,l=this.nodeName.toLowerCase();switch("label"===l&&c.find("input, textarea, select").leng [...]
+//# sourceMappingURL=jquery.contextMenu.min.js.map
diff --git a/emperor/support_files/vendor/js/jquery.event.drag-2.2.min.js b/emperor/support_files/vendor/js/jquery.event.drag-2.2.min.js
new file mode 100644
index 0000000..1994db8
--- /dev/null
+++ b/emperor/support_files/vendor/js/jquery.event.drag-2.2.min.js
@@ -0,0 +1,6 @@
+/*! 
+ * jquery.event.drag - v 2.2
+ * Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
+ * Open Source MIT License - http://threedubmedia.com/code/license
+ */
+;(function(e){e.fn.drag=function(k,g,j){var i=typeof k=="string"?k:"",h=e.isFunction(k)?k:e.isFunction(g)?g:null;if(i.indexOf("drag")!==0){i="drag"+i}j=(k==h?g:j)||{};return h?this.bind(i,j,h):this.trigger(i)};var b=e.event,a=b.special,d=a.drag={defaults:{which:1,distance:0,not:":input",handle:null,relative:false,drop:true,click:false},datakey:"dragdata",noBubble:true,add:function(i){var h=e.data(this,d.datakey),g=i.data||{};h.related+=1;e.each(d.defaults,function(j,k){if(g[j]!==undefine [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/jquery.ui.position.min.js b/emperor/support_files/vendor/js/jquery.ui.position.min.js
new file mode 100644
index 0000000..899360e
--- /dev/null
+++ b/emperor/support_files/vendor/js/jquery.ui.position.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.11.4 - 2015-03-13
+* http://jqueryui.com
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){return function(){function e(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{wi [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/require-2.1.22.min.js b/emperor/support_files/vendor/js/require-2.1.22.min.js
new file mode 100644
index 0000000..651902f
--- /dev/null
+++ b/emperor/support_files/vendor/js/require-2.1.22.min.js
@@ -0,0 +1,37 @@
+/*
+ RequireJS 2.1.22 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
+ Available via the MIT or new BSD license.
+ see: http://github.com/jrburke/requirejs for details
+*/
+var requirejs,require,define;
+(function(ha){function L(b){return"[object Function]"===R.call(b)}function M(b){return"[object Array]"===R.call(b)}function x(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function Y(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));--d);}}function w(b,c){return la.call(b,c)}function g(b,c){return w(b,c)&&b[c]}function E(b,c){for(var d in b)if(w(b,d)&&c(b[d],d))break}function Z(b,c,d,k){c&&E(c,function(c,g){if(d||!w(b,g))!k||"object"!==typeof c||!c||M(c)| [...]
+RegExp?b[g]=c:(b[g]||(b[g]={}),Z(b[g],c,d,k))});return b}function y(b,c){return function(){return c.apply(b,arguments)}}function ia(b){throw b;}function ja(b){if(!b)return b;var c=ha;x(b.split("."),function(b){c=c[b]});return c}function G(b,c,d,g){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=g;d&&(c.originalError=d);return c}function ma(b){function c(a,n,b){var f,l,c,d,h,k,e,A;n=n&&n.split("/");var q=m.map,p=q&&q["*"];if(a){a=a.split("/");l=a.l [...]
+V.test(a[l])&&(a[l]=a[l].replace(V,""));"."===a[0].charAt(0)&&n&&(l=n.slice(0,n.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)d=l[c],"."===d?(l.splice(c,1),--c):".."===d&&0!==c&&(1!==c||".."!==l[2])&&".."!==l[c-1]&&0<c&&(l.splice(c-1,2),c-=2);a=a.join("/")}if(b&&q&&(n||p)){l=a.split("/");c=l.length;a:for(;0<c;--c){h=l.slice(0,c).join("/");if(n)for(d=n.length;0<d;--d)if(b=g(q,n.slice(0,d).join("/")))if(b=g(b,h)){f=b;k=c;break a}!e&&p&&g(p,h)&&(e=g(p,h),A=c)}!f&&e&&(f=e,k=A);f&&(l.sp [...]
+f),a=l.join("/"))}return(f=g(m.pkgs,a))?f:a}function d(a){F&&x(document.getElementsByTagName("script"),function(n){if(n.getAttribute("data-requiremodule")===a&&n.getAttribute("data-requirecontext")===h.contextName)return n.parentNode.removeChild(n),!0})}function p(a){var n=g(m.paths,a);if(n&&M(n)&&1<n.length)return n.shift(),h.require.undef(a),h.makeRequire(null,{skipMap:!0})([a]),!0}function e(a){var n,b=a?a.indexOf("!"):-1;-1<b&&(n=a.substring(0,b),a=a.substring(b+1,a.length));return[n [...]
+n,b,f){var l,d,z=null,k=n?n.name:null,m=a,q=!0,A="";a||(q=!1,a="_ at r"+(R+=1));a=e(a);z=a[0];a=a[1];z&&(z=c(z,k,f),d=g(r,z));a&&(z?A=d&&d.normalize?d.normalize(a,function(a){return c(a,k,f)}):-1===a.indexOf("!")?c(a,k,f):a:(A=c(a,k,f),a=e(A),z=a[0],A=a[1],b=!0,l=h.nameToUrl(A)));b=!z||d||b?"":"_unnormalized"+(U+=1);return{prefix:z,name:A,parentMap:n,unnormalized:!!b,url:l,originalName:m,isDefine:q,id:(z?z+"!"+A:A)+b}}function u(a){var b=a.id,c=g(t,b);c||(c=t[b]=new h.Module(a));return c}fu [...]
+b,c){var f=a.id,l=g(t,f);if(!w(r,f)||l&&!l.defineEmitComplete)if(l=u(a),l.error&&"error"===b)c(l.error);else l.on(b,c);else"defined"===b&&c(r[f])}function B(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(x(c,function(b){if(b=g(t,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)k.onError(a)}function C(){W.length&&(x(W,function(a){var b=a[0];"string"===typeof b&&(h.defQueueMap[b]=!0);H.push(a)}),W=[])}function D(a){delete t[a];delete aa[a]}function K(a,b,c){var f=a.map.id;a.e [...]
+a.error):(b[f]=!0,x(a.depMaps,function(f,d){var h=f.id,k=g(t,h);!k||a.depMatched[d]||c[h]||(g(b,h)?(a.defineDep(d,r[h]),a.check()):K(k,b,c))}),c[f]=!0)}function I(){var a,b,c=(a=1E3*m.waitSeconds)&&h.startTime+a<(new Date).getTime(),f=[],l=[],k=!1,g=!0;if(!ba){ba=!0;E(aa,function(a){var h=a.map,e=h.id;if(a.enabled&&(h.isDefine||l.push(a),!a.error))if(!a.inited&&c)p(e)?k=b=!0:(f.push(e),d(e));else if(!a.inited&&a.fetched&&h.isDefine&&(k=!0,!h.prefix))return g=!1});if(c&&f.length)return a= [...]
+"Load timeout for modules: "+f,null,f),a.contextName=h.contextName,B(a);g&&x(l,function(a){K(a,{},{})});c&&!b||!k||!F&&!ka||ca||(ca=setTimeout(function(){ca=0;I()},50));ba=!1}}function J(a){w(r,a[0])||u(q(a[0],null,!0)).init(a[1],a[2])}function P(a){a=a.currentTarget||a.srcElement;var b=h.onScriptLoad;a.detachEvent&&!da?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=h.onScriptError;a.detachEvent&&!da||a.removeEventListener("error",b,!1);return{node:a,id:a&&a.g [...]
+function Q(){var a;for(C();H.length;){a=H.shift();if(null===a[0])return B(G("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));J(a)}h.defQueueMap={}}var ba,ea,h,S,ca,m={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},t={},aa={},fa={},H=[],r={},X={},ga={},R=1,U=1;S={require:function(a){return a.require?a.require:a.require=h.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports [...]
+{}},module:function(a){return a.module?a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return g(m.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};ea=function(a){this.events=g(fa,a.id)||{};this.map=a;this.shim=g(m.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};ea.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=y(this,function(a){this. [...]
+a)}));this.depMaps=a&&a.slice(0);this.errback=c;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,--this.depCount,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;h.startTime=(new Date).getTime();var a=this.map;if(this.shim)h.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],y(this,function(){return a.prefix?this.callPlugin():this.load()}));el [...]
+this.callPlugin():this.load()}},load:function(){var a=this.map.url;X[a]||(X[a]=!0,h.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(!this.inited)w(h.defQueueMap,c)||this.fetch();else if(this.error)this.emit("error",this.error);else if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(L(l)){try{f=h.execCb(c,l,b,f)}catch(d){a=d}this.map.isDefine&&void 0===f&&((b=this.mo [...]
+this.usingExports&&(f=this.exports));if(a){if(this.events.error&&this.map.isDefine||k.onError!==ia)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",B(this.error=a);if("undefined"!==typeof console&&console.error)console.error(a);else k.onError(a)}}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,k.onResourceLoad)){var e=[];x(this.depMaps,function(a){e.push(a.normalizedMap||a)});k.onReso [...]
+this.map,e)}D(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}},callPlugin:function(){var a=this.map,b=a.id,d=q(a.prefix);this.depMaps.push(d);v(d,"defined",y(this,function(f){var l,d,e=g(ga,this.map.id),N=this.map.name,p=this.map.parentMap?this.map.parentMap.name:null,r=h.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(N=f.normalize(N, [...]
+p,!0)})||""),d=q(a.prefix+"!"+N,this.map.parentMap),v(d,"defined",y(this,function(a){this.map.normalizedMap=d;this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),f=g(t,d.id)){this.depMaps.push(d);if(this.events.error)f.on("error",y(this,function(a){this.emit("error",a)}));f.enable()}}else e?(this.map.url=h.nameToUrl(e),this.load()):(l=y(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=y(this,function(a){this.inited=!0;this.error=a;a.requireMod [...]
+E(t,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&D(a.map.id)});B(a)}),l.fromText=y(this,function(f,c){var d=a.name,e=q(d),N=T;c&&(f=c);N&&(T=!1);u(e);w(m.config,b)&&(m.config[d]=m.config[b]);try{k.exec(f)}catch(g){return B(G("fromtexteval","fromText eval for "+b+" failed: "+g,g,[b]))}N&&(T=!0);this.depMaps.push(e);h.completeLoad(d);r([d],l)}),f.load(a.name,r,l,m))}));h.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){aa[this.map.id]=this;this.enabling=this.enabled=!0;x(t [...]
+y(this,function(a,b){var c,f;if("string"===typeof a){a=q(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=g(S,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;v(a,"defined",y(this,function(a){this.undefed||(this.defineDep(b,a),this.check())}));this.errback?v(a,"error",y(this,this.errback)):this.events.error&&v(a,"error",y(this,function(a){this.emit("error",a)}))}c=a.id;f=t[c];w(S,c)||!f||f.enabled||h.enable(a,this)}));E(this.pluginMaps,y(t [...]
+g(t,a.id);b&&!b.enabled&&h.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){x(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};h={config:m,contextName:b,registry:t,defined:r,urlFetched:X,defQueue:H,defQueueMap:{},Module:ea,makeModuleMap:q,nextTick:k.nextTick,onError:B,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=m.shim,c [...]
+bundles:!0,config:!0,map:!0};E(a,function(a,b){c[b]?(m[b]||(m[b]={}),Z(m[b],a,!0,!0)):m[b]=a});a.bundles&&E(a.bundles,function(a,b){x(a,function(a){a!==b&&(ga[a]=b)})});a.shim&&(E(a.shim,function(a,c){M(a)&&(a={deps:a});!a.exports&&!a.init||a.exportsFn||(a.exportsFn=h.makeShimExports(a));b[c]=a}),m.shim=b);a.packages&&x(a.packages,function(a){var b;a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(m.paths[b]=a.location);m.pkgs[b]=a.name+"/"+(a.main||"main").replace(na,"").replace(V, [...]
+function(a,b){a.inited||a.map.unnormalized||(a.map=q(b,null,!0))});(a.deps||a.callback)&&h.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ha,arguments));return b||a.exports&&ja(a.exports)}},makeRequire:function(a,n){function e(c,d,g){var m,p;n.enableBuildCallback&&d&&L(d)&&(d.__requireJsBuild=!0);if("string"===typeof c){if(L(d))return B(G("requireargs","Invalid require call"),g);if(a&&w(S,c))return S[c](t[a.id]);if(k.get)return [...]
+c,a,e);m=q(c,a,!1,!0);m=m.id;return w(r,m)?r[m]:B(G("notloaded",'Module name "'+m+'" has not been loaded yet for context: '+b+(a?"":". Use require([])")))}Q();h.nextTick(function(){Q();p=u(q(null,a));p.skipMap=n.skipMap;p.init(c,d,g,{enabled:!0});I()});return e}n=n||{};Z(e,{isBrowser:F,toUrl:function(b){var d,e=b.lastIndexOf("."),n=b.split("/")[0];-1!==e&&("."!==n&&".."!==n||1<e)&&(d=b.substring(e,b.length),b=b.substring(0,e));return h.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b) [...]
+q(b,a,!1,!0).id)},specified:function(b){b=q(b,a,!1,!0).id;return w(r,b)||w(t,b)}});a||(e.undef=function(b){C();var c=q(b,a,!0),e=g(t,b);e.undefed=!0;d(b);delete r[b];delete X[c.url];delete fa[b];Y(H,function(a,c){a[0]===b&&H.splice(c,1)});delete h.defQueueMap[b];e&&(e.events.defined&&(fa[b]=e.events),D(b))});return e},enable:function(a){g(t,a.id)&&u(a).enable()},completeLoad:function(a){var b,c,d=g(m.shim,a)||{},e=d.exports;for(C();H.length;){c=H.shift();if(null===c[0]){c[0]=a;if(b)break [...]
+a&&(b=!0);J(c)}h.defQueueMap={};c=g(t,a);if(!b&&!w(r,a)&&c&&!c.inited)if(!m.enforceDefine||e&&ja(e))J([a,d.deps||[],d.exportsFn]);else return p(a)?void 0:B(G("nodefine","No define call for "+a,null,[a]));I()},nameToUrl:function(a,b,c){var d,e,p;(d=g(m.pkgs,a))&&(a=d);if(d=g(ga,a))return h.nameToUrl(d,b,c);if(k.jsExtRegExp.test(a))d=a+(b||"");else{d=m.paths;a=a.split("/");for(e=a.length;0<e;--e)if(p=a.slice(0,e).join("/"),p=g(d,p)){M(p)&&(p=p[0]);a.splice(0,e,p);break}d=a.join("/");d+=b|| [...]
+c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":m.baseUrl)+d}return m.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+m.urlArgs):d},load:function(a,b){k.load(h,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||oa.test((a.currentTarget||a.srcElement).readyState))O=null,a=P(a),h.completeLoad(a.id)},onScriptError:function(a){var b=P(a);if(!p(b.id)){var c=[];E(t,function(a,d){0!==d.indexOf("_ at r")&&x(a.depMaps,function(a){a.id===b.id&&c.pu [...]
+return B(G("scripterror",'Script error for "'+b.id+(c.length?'", needed by: '+c.join(", "):'"'),a,[b.id]))}}};h.require=h.makeRequire();return h}function pa(){if(O&&"interactive"===O.readyState)return O;Y(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return O=b});return O}var k,C,D,I,P,J,O,Q,u,U,qa=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ra=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,V=/\.js$/,na=/^\.\//;C=Object.prototype;var R=C.toString,la [...]
+F=!("undefined"===typeof window||"undefined"===typeof navigator||!window.document),ka=!F&&"undefined"!==typeof importScripts,oa=F&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,da="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),K={},v={},W=[],T=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(L(requirejs))return;v=requirejs;requirejs=void 0}"undefined"===typeof require||L(require)||(v=require,require=void 0);k=requirejs=fu [...]
+c,d,p){var e,q="_";M(b)||"string"===typeof b||(e=b,M(c)?(b=c,c=d,d=p):b=[]);e&&e.context&&(q=e.context);(p=g(K,q))||(p=K[q]=k.s.newContext(q));e&&p.configure(e);return p.require(b,c,d)};k.config=function(b){return k(b)};k.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=k);k.version="2.1.22";k.jsExtRegExp=/^\/|:|\?|\.js$/;k.isBrowser=F;C=k.s={contexts:K,newContext:ma};k({});x(["toUrl","undef","defined","specified"],function(b){k[b]= [...]
+K._;return c.require[b].apply(c,arguments)}});F&&(D=C.head=document.getElementsByTagName("head")[0],I=document.getElementsByTagName("base")[0])&&(D=C.head=I.parentNode);k.onError=ia;k.createNode=function(b,c,d){c=b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};k.load=function(b,c,d){var g=b&&b.config||{},e;if(F){e=k.createNode(g,c,d);if(g.onNodeCre [...]
+g,c,d);e.setAttribute("data-requirecontext",b.contextName);e.setAttribute("data-requiremodule",c);!e.attachEvent||e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code")||da?(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)):(T=!0,e.attachEvent("onreadystatechange",b.onScriptLoad));e.src=d;Q=e;I?D.insertBefore(e,I):D.appendChild(e);Q=null;return e}if(ka)try{importScripts(d),b.completeLoad(c)}catch(q){b.onError(G("importscripts [...]
+c+" at "+d,q,[c]))}};F&&!v.skipDataMain&&Y(document.getElementsByTagName("script"),function(b){D||(D=b.parentNode);if(P=b.getAttribute("data-main"))return u=P,v.baseUrl||(J=u.split("/"),u=J.pop(),U=J.length?J.join("/")+"/":"./",v.baseUrl=U),u=u.replace(V,""),k.jsExtRegExp.test(u)&&(u=P),v.deps=v.deps?v.deps.concat(u):[u],!0});define=function(b,c,d){var g,e;"string"!==typeof b&&(d=c,c=b,b=null);M(c)||(d=c,c=null);!c&&L(d)&&(c=[],d.length&&(d.toString().replace(qa,"").replace(ra,function(b [...]
+c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));T&&(g=Q||pa())&&(b||(b=g.getAttribute("data-requiremodule")),e=K[g.getAttribute("data-requirecontext")]);e?(e.defQueue.push([b,c,d]),e.defQueueMap[b]=!0):W.push([b,c,d])};define.amd={jQuery:!0};k.exec=function(b){return eval(b)};k(v)}})(this);
diff --git a/emperor/support_files/vendor/js/slick.core.min.js b/emperor/support_files/vendor/js/slick.core.min.js
new file mode 100644
index 0000000..96e95f2
--- /dev/null
+++ b/emperor/support_files/vendor/js/slick.core.min.js
@@ -0,0 +1 @@
+!function(t){function i(){var t=!1,i=!1;this.stopPropagation=function(){t=!0},this.isPropagationStopped=function(){return t},this.stopImmediatePropagation=function(){i=!0},this.isImmediatePropagationStopped=function(){return i}}function n(){var t=[];this.subscribe=function(i){t.push(i)},this.unsubscribe=function(i){for(var n=t.length-1;n>=0;n--)t[n]===i&&t.splice(n,1)},this.notify=function(n,o,e){o=o||new i,e=e||this;for(var r,s=0;s<t.length&&!o.isPropagationStopped()&&!o.isImmediateProp [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/slick.editors.min.js b/emperor/support_files/vendor/js/slick.editors.min.js
new file mode 100644
index 0000000..cb3a05c
--- /dev/null
+++ b/emperor/support_files/vendor/js/slick.editors.min.js
@@ -0,0 +1 @@
+!function(e){function t(t){var i,n;this.init=function(){i=e("<INPUT type=text class='editor-text' />").appendTo(t.container).bind("keydown.nav",function(t){(t.keyCode===e.ui.keyCode.LEFT||t.keyCode===e.ui.keyCode.RIGHT)&&t.stopImmediatePropagation()}).focus().select()},this.destroy=function(){i.remove()},this.focus=function(){i.focus()},this.getValue=function(){return i.val()},this.setValue=function(e){i.val(e)},this.loadValue=function(e){n=e[t.column.field]||"",i.val(n),i[0].defaultValu [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/slick.formatters.min.js b/emperor/support_files/vendor/js/slick.formatters.min.js
new file mode 100644
index 0000000..2ad3987
--- /dev/null
+++ b/emperor/support_files/vendor/js/slick.formatters.min.js
@@ -0,0 +1 @@
+!function(e){function n(e,n,r,t,o){return null==r||""===r?"-":50>r?"<span style='color:red;font-weight:bold;'>"+r+"%</span>":"<span style='color:green'>"+r+"%</span>"}function r(e,n,r,t,o){if(null==r||""===r)return"";var c;return c=30>r?"red":70>r?"silver":"green","<span class='percent-complete-bar' style='background:"+c+";width:"+r+"%'></span>"}function t(e,n,r,t,o){return r?"Yes":"No"}function o(e,n,r,t,o){return r?"<div class='ui-state-default ui-corner-all'><span class='ui-icon ui-ic [...]
diff --git a/emperor/support_files/vendor/js/slick.grid.min.js b/emperor/support_files/vendor/js/slick.grid.min.js
new file mode 100644
index 0000000..a44de2e
--- /dev/null
+++ b/emperor/support_files/vendor/js/slick.grid.min.js
@@ -0,0 +1,2 @@
+if("undefined"==typeof jQuery)throw"SlickGrid requires jquery module to be loaded";if(!jQuery.fn.drag)throw"SlickGrid requires jquery.event.drag module to be loaded";if("undefined"==typeof Slick)throw"slick.core.js not loaded";!function($){function SlickGrid(container,data,columns,options){function init(){if($container=$(container),$container.length<1)throw new Error("SlickGrid requires a valid container, "+container+" does not exist in the DOM.");cacheCssForHiddenInit(),maxSupportedCssH [...]
+page=h==viewportH?0:Math.min(n-1,Math.floor(scrollTop*((th-viewportH)/(h-viewportH))*(1/ph))),offset=Math.round(page*cj),o!=offset&&invalidateAllRows()}(t||e)&&(h_render&&clearTimeout(h_render),(Math.abs(lastRenderedScrollTop-scrollTop)>20||Math.abs(lastRenderedScrollLeft-scrollLeft)>20)&&(options.forceSyncScrolling||Math.abs(lastRenderedScrollTop-scrollTop)<viewportH&&Math.abs(lastRenderedScrollLeft-scrollLeft)<viewportW?render():h_render=setTimeout(render,50),trigger(self.onViewportCha [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/spectrum.min.js b/emperor/support_files/vendor/js/spectrum.min.js
new file mode 100644
index 0000000..33813be
--- /dev/null
+++ b/emperor/support_files/vendor/js/spectrum.min.js
@@ -0,0 +1 @@
+!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof exports&&"object"==typeof module?module.exports=t(require("jquery")):t(jQuery)}(function(t,e){"use strict";function r(e,r,n,a){for(var i=[],s=0;s<e.length;s++){var o=e[s];if(o){var l=tinycolor(o),c=l.toHsl().l<.5?"sp-thumb-el sp-thumb-dark":"sp-thumb-el sp-thumb-light";c+=tinycolor.equals(r,o)?" sp-thumb-active":"";var f=l.toString(a.preferredFormat||"rgb"),u=b?"background-color:"+l.toRg [...]
\ No newline at end of file
diff --git a/emperor/support_files/vendor/js/three.js-plugins/ColorConverter.js b/emperor/support_files/vendor/js/three.js-plugins/ColorConverter.js
new file mode 100644
index 0000000..8a49f05
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.js-plugins/ColorConverter.js
@@ -0,0 +1,64 @@
+/**
+ * @author bhouston / http://exocortex.com/
+ * @author zz85 / http://github.com/zz85
+ */
+
+THREE.ColorConverter = {
+
+	setHSV: function ( color, h, s, v ) {
+
+		// https://gist.github.com/xpansive/1337890#file-index-js
+
+		h = THREE.Math.euclideanModulo( h, 1 );
+		s = THREE.Math.clamp( s, 0, 1 );
+		v = THREE.Math.clamp( v, 0, 1 );
+
+		return color.setHSL( h, ( s * v ) / ( ( h = ( 2 - s ) * v ) < 1 ? h : ( 2 - h ) ), h * 0.5 );
+
+	},
+
+	getHSV: function( color ) {
+
+		var hsl = color.getHSL();
+
+		// based on https://gist.github.com/xpansive/1337890#file-index-js
+		hsl.s *= ( hsl.l < 0.5 ) ? hsl.l : ( 1 - hsl.l );
+
+		return {
+			h: hsl.h,
+			s: 2 * hsl.s / ( hsl.l + hsl.s ),
+			v: hsl.l + hsl.s
+		};
+
+	},
+
+	// where c, m, y, k is between 0 and 1
+	
+	setCMYK: function ( color, c, m, y, k ) {
+
+		var r = ( 1 - c ) * ( 1 - k );
+		var g = ( 1 - m ) * ( 1 - k );
+		var b = ( 1 - y ) * ( 1 - k );
+
+		return color.setRGB( r, g, b );
+
+	},
+
+	getCMYK: function ( color ) {
+
+		var r = color.r;
+		var g = color.g;
+		var b = color.b;
+		var k = 1 - Math.max( r, g, b );
+		var c = ( 1 - r - k ) / ( 1 - k );
+		var m = ( 1 - g - k ) / ( 1 - k );
+		var y = ( 1 - b - k ) / ( 1 - k );
+
+		return {
+			c: c, m: m, y: y, k: k
+		};
+
+	}
+
+
+};
diff --git a/emperor/support_files/vendor/js/three.js-plugins/Detector.js b/emperor/support_files/vendor/js/three.js-plugins/Detector.js
new file mode 100644
index 0000000..95a2724
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.js-plugins/Detector.js
@@ -0,0 +1,78 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+var Detector = {
+
+	canvas: !! window.CanvasRenderingContext2D,
+	webgl: ( function () {
+
+		try {
+
+			var canvas = document.createElement( 'canvas' ); return !! ( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) );
+
+		} catch ( e ) {
+
+			return false;
+
+		}
+
+	} )(),
+	workers: !! window.Worker,
+	fileapi: window.File && window.FileReader && window.FileList && window.Blob,
+
+	getWebGLErrorMessage: function () {
+
+		var element = document.createElement( 'div' );
+		element.id = 'webgl-error-message';
+		element.style.fontFamily = 'monospace';
+		element.style.fontSize = '13px';
+		element.style.fontWeight = 'normal';
+		element.style.textAlign = 'center';
+		element.style.background = '#fff';
+		element.style.color = '#000';
+		element.style.padding = '1.5em';
+		element.style.width = '400px';
+		element.style.margin = '5em auto 0';
+
+		if ( ! this.webgl ) {
+
+			element.innerHTML = window.WebGLRenderingContext ? [
+				'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />',
+				'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
+			].join( '\n' ) : [
+				'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>',
+				'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
+			].join( '\n' );
+
+		}
+
+		return element;
+
+	},
+
+	addGetWebGLMessage: function ( parameters ) {
+
+		var parent, id, element;
+
+		parameters = parameters || {};
+
+		parent = parameters.parent !== undefined ? parameters.parent : document.body;
+		id = parameters.id !== undefined ? parameters.id : 'oldie';
+
+		element = Detector.getWebGLErrorMessage();
+		element.id = id;
+
+		parent.appendChild( element );
+
+	}
+
+};
+
+// browserify support
+if ( typeof module === 'object' ) {
+
+	module.exports = Detector;
+
+}
diff --git a/emperor/support_files/vendor/js/three.js-plugins/OrbitControls.js b/emperor/support_files/vendor/js/three.js-plugins/OrbitControls.js
new file mode 100644
index 0000000..500187b
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.js-plugins/OrbitControls.js
@@ -0,0 +1,1115 @@
+/**
+ * @author qiao / https://github.com/qiao
+ * @author mrdoob / http://mrdoob.com
+ * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author erich666 / http://erichaines.com
+ */
+/*global THREE, console */
+
+( function () {
+
+	function OrbitConstraint ( object ) {
+
+		this.object = object;
+
+		// "target" sets the location of focus, where the object orbits around
+		// and where it pans with respect to.
+		this.target = new THREE.Vector3();
+
+		// Limits to how far you can dolly in and out ( PerspectiveCamera only )
+		this.minDistance = 0;
+		this.maxDistance = Infinity;
+
+		// Limits to how far you can zoom in and out ( OrthographicCamera only )
+		this.minZoom = 0;
+		this.maxZoom = Infinity;
+
+		// How far you can orbit vertically, upper and lower limits.
+		// Range is 0 to Math.PI radians.
+		this.minPolarAngle = 0; // radians
+		this.maxPolarAngle = Math.PI; // radians
+
+		// How far you can orbit horizontally, upper and lower limits.
+		// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
+		this.minAzimuthAngle = - Infinity; // radians
+		this.maxAzimuthAngle = Infinity; // radians
+
+		// Set to true to enable damping (inertia)
+		// If damping is enabled, you must call controls.update() in your animation loop
+		this.enableDamping = false;
+		this.dampingFactor = 0.25;
+
+		////////////
+		// internals
+
+		var scope = this;
+
+		var EPS = 0.000001;
+
+		// Current position in spherical coordinate system.
+		var theta;
+		var phi;
+
+		// Pending changes
+		var phiDelta = 0;
+		var thetaDelta = 0;
+		var scale = 1;
+		var panOffset = new THREE.Vector3();
+		var zoomChanged = false;
+
+		// API
+
+		this.getPolarAngle = function () {
+
+			return phi;
+
+		};
+
+		this.getAzimuthalAngle = function () {
+
+			return theta;
+
+		};
+
+		this.rotateLeft = function ( angle ) {
+
+			thetaDelta -= angle;
+
+		};
+
+		this.rotateUp = function ( angle ) {
+
+			phiDelta -= angle;
+
+		};
+
+		// pass in distance in world space to move left
+		this.panLeft = function() {
+
+			var v = new THREE.Vector3();
+
+			return function panLeft ( distance ) {
+
+				var te = this.object.matrix.elements;
+
+				// get X column of matrix
+				v.set( te[ 0 ], te[ 1 ], te[ 2 ] );
+				v.multiplyScalar( - distance );
+
+				panOffset.add( v );
+
+			};
+
+		}();
+
+		// pass in distance in world space to move up
+		this.panUp = function() {
+
+			var v = new THREE.Vector3();
+
+			return function panUp ( distance ) {
+
+				var te = this.object.matrix.elements;
+
+				// get Y column of matrix
+				v.set( te[ 4 ], te[ 5 ], te[ 6 ] );
+				v.multiplyScalar( distance );
+
+				panOffset.add( v );
+
+			};
+
+		}();
+
+		// pass in x,y of change desired in pixel space,
+		// right and down are positive
+		this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) {
+
+			if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+				// perspective
+				var position = scope.object.position;
+				var offset = position.clone().sub( scope.target );
+				var targetDistance = offset.length();
+
+				// half of the fov is center to top of screen
+				targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
+
+				// we actually don't use screenWidth, since perspective camera is fixed to screen height
+				scope.panLeft( 2 * deltaX * targetDistance / screenHeight );
+				scope.panUp( 2 * deltaY * targetDistance / screenHeight );
+
+			} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+				// orthographic
+				scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth );
+				scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight );
+
+			} else {
+
+				// camera neither orthographic or perspective
+				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
+
+			}
+
+		};
+
+		this.dollyIn = function ( dollyScale ) {
+
+			if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+				scale /= dollyScale;
+
+			} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+				scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );
+				scope.object.updateProjectionMatrix();
+				zoomChanged = true;
+
+			} else {
+
+				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+
+			}
+
+		};
+
+		this.dollyOut = function ( dollyScale ) {
+
+			if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+				scale *= dollyScale;
+
+			} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+				scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );
+				scope.object.updateProjectionMatrix();
+				zoomChanged = true;
+
+			} else {
+
+				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+
+			}
+
+		};
+
+		this.update = function() {
+
+			var offset = new THREE.Vector3();
+
+			// so camera.up is the orbit axis
+			var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
+			var quatInverse = quat.clone().inverse();
+
+			var lastPosition = new THREE.Vector3();
+			var lastQuaternion = new THREE.Quaternion();
+
+			return function () {
+
+				var position = this.object.position;
+
+				offset.copy( position ).sub( this.target );
+
+				// rotate offset to "y-axis-is-up" space
+				offset.applyQuaternion( quat );
+
+				// angle from z-axis around y-axis
+
+				theta = Math.atan2( offset.x, offset.z );
+
+				// angle from y-axis
+
+				phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
+
+				theta += thetaDelta;
+				phi += phiDelta;
+
+				// restrict theta to be between desired limits
+				theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
+
+				// restrict phi to be between desired limits
+				phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
+
+				// restrict phi to be betwee EPS and PI-EPS
+				phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
+
+				var radius = offset.length() * scale;
+
+				// restrict radius to be between desired limits
+				radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
+
+				// move target to panned location
+				this.target.add( panOffset );
+
+				offset.x = radius * Math.sin( phi ) * Math.sin( theta );
+				offset.y = radius * Math.cos( phi );
+				offset.z = radius * Math.sin( phi ) * Math.cos( theta );
+
+				// rotate offset back to "camera-up-vector-is-up" space
+				offset.applyQuaternion( quatInverse );
+
+				position.copy( this.target ).add( offset );
+
+				this.object.lookAt( this.target );
+
+				if ( this.enableDamping === true ) {
+
+					thetaDelta *= ( 1 - this.dampingFactor );
+					phiDelta *= ( 1 - this.dampingFactor );
+
+				} else {
+
+					thetaDelta = 0;
+					phiDelta = 0;
+
+				}
+
+				scale = 1;
+				panOffset.set( 0, 0, 0 );
+
+				// update condition is:
+				// min(camera displacement, camera rotation in radians)^2 > EPS
+				// using small-angle approximation cos(x/2) = 1 - x^2 / 8
+
+				if ( zoomChanged ||
+					 lastPosition.distanceToSquared( this.object.position ) > EPS ||
+				    8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) {
+
+					lastPosition.copy( this.object.position );
+					lastQuaternion.copy( this.object.quaternion );
+					zoomChanged = false;
+
+					return true;
+
+				}
+
+				return false;
+
+			};
+
+		}();
+
+	};
+
+
+	// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
+	// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
+	// supported.
+	//
+	//    Orbit - left mouse / touch: one finger move
+	//    Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
+	//    Pan - right mouse, or arrow keys / touch: three finter swipe
+
+	THREE.OrbitControls = function ( object, domElement ) {
+
+		var constraint = new OrbitConstraint( object );
+
+		this.domElement = ( domElement !== undefined ) ? domElement : document;
+
+		// API
+
+		Object.defineProperty( this, 'constraint', {
+
+			get: function() {
+
+				return constraint;
+
+			}
+
+		} );
+
+		this.getPolarAngle = function () {
+
+			return constraint.getPolarAngle();
+
+		};
+
+		this.getAzimuthalAngle = function () {
+
+			return constraint.getAzimuthalAngle();
+
+		};
+
+		// Set to false to disable this control
+		this.enabled = true;
+
+		// center is old, deprecated; use "target" instead
+		this.center = this.target;
+
+		// This option actually enables dollying in and out; left as "zoom" for
+		// backwards compatibility.
+		// Set to false to disable zooming
+		this.enableZoom = true;
+		this.zoomSpeed = 1.0;
+
+		// Set to false to disable rotating
+		this.enableRotate = true;
+		this.rotateSpeed = 1.0;
+
+		// Set to false to disable panning
+		this.enablePan = true;
+		this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
+
+		// Set to true to automatically rotate around the target
+		// If auto-rotate is enabled, you must call controls.update() in your animation loop
+		this.autoRotate = false;
+		this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
+
+		// Set to false to disable use of the keys
+		this.enableKeys = true;
+
+		// The four arrow keys
+		this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
+
+		// Mouse buttons
+		this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
+
+		////////////
+		// internals
+
+		var scope = this;
+
+		var rotateStart = new THREE.Vector2();
+		var rotateEnd = new THREE.Vector2();
+		var rotateDelta = new THREE.Vector2();
+
+		var panStart = new THREE.Vector2();
+		var panEnd = new THREE.Vector2();
+		var panDelta = new THREE.Vector2();
+
+		var dollyStart = new THREE.Vector2();
+		var dollyEnd = new THREE.Vector2();
+		var dollyDelta = new THREE.Vector2();
+
+		var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
+
+		var state = STATE.NONE;
+
+		// for reset
+
+		this.target0 = this.target.clone();
+		this.position0 = this.object.position.clone();
+		this.zoom0 = this.object.zoom;
+
+		// events
+
+		var changeEvent = { type: 'change' };
+		var startEvent = { type: 'start' };
+		var endEvent = { type: 'end' };
+
+		// pass in x,y of change desired in pixel space,
+		// right and down are positive
+		function pan( deltaX, deltaY ) {
+
+			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+			constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight );
+
+		}
+
+		this.update = function () {
+
+			if ( this.autoRotate && state === STATE.NONE ) {
+
+				constraint.rotateLeft( getAutoRotationAngle() );
+
+			}
+
+			if ( constraint.update() === true ) {
+
+				this.dispatchEvent( changeEvent );
+
+			}
+
+		};
+
+		this.reset = function () {
+
+			state = STATE.NONE;
+
+			this.target.copy( this.target0 );
+			this.object.position.copy( this.position0 );
+			this.object.zoom = this.zoom0;
+
+			this.object.updateProjectionMatrix();
+			this.dispatchEvent( changeEvent );
+
+			this.update();
+
+		};
+
+		function getAutoRotationAngle() {
+
+			return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
+
+		}
+
+		function getZoomScale() {
+
+			return Math.pow( 0.95, scope.zoomSpeed );
+
+		}
+
+		function onMouseDown( event ) {
+
+			if ( scope.enabled === false ) return;
+
+			event.preventDefault();
+
+			if ( event.button === scope.mouseButtons.ORBIT ) {
+
+				if ( scope.enableRotate === false ) return;
+
+				state = STATE.ROTATE;
+
+				rotateStart.set( event.clientX, event.clientY );
+
+			} else if ( event.button === scope.mouseButtons.ZOOM ) {
+
+				if ( scope.enableZoom === false ) return;
+
+				state = STATE.DOLLY;
+
+				dollyStart.set( event.clientX, event.clientY );
+
+			} else if ( event.button === scope.mouseButtons.PAN ) {
+
+				if ( scope.enablePan === false ) return;
+
+				state = STATE.PAN;
+
+				panStart.set( event.clientX, event.clientY );
+
+			}
+
+			if ( state !== STATE.NONE ) {
+
+				document.addEventListener( 'mousemove', onMouseMove, false );
+				document.addEventListener( 'mouseup', onMouseUp, false );
+				scope.dispatchEvent( startEvent );
+
+			}
+
+		}
+
+		function onMouseMove( event ) {
+
+			if ( scope.enabled === false ) return;
+
+			event.preventDefault();
+
+			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+			if ( state === STATE.ROTATE ) {
+
+				if ( scope.enableRotate === false ) return;
+
+				rotateEnd.set( event.clientX, event.clientY );
+				rotateDelta.subVectors( rotateEnd, rotateStart );
+
+				// rotating across whole screen goes 360 degrees around
+				constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
+
+				// rotating up and down along whole screen attempts to go 360, but limited to 180
+				constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
+
+				rotateStart.copy( rotateEnd );
+
+			} else if ( state === STATE.DOLLY ) {
+
+				if ( scope.enableZoom === false ) return;
+
+				dollyEnd.set( event.clientX, event.clientY );
+				dollyDelta.subVectors( dollyEnd, dollyStart );
+
+				if ( dollyDelta.y > 0 ) {
+
+					constraint.dollyIn( getZoomScale() );
+
+				} else if ( dollyDelta.y < 0 ) {
+
+					constraint.dollyOut( getZoomScale() );
+
+				}
+
+				dollyStart.copy( dollyEnd );
+
+			} else if ( state === STATE.PAN ) {
+
+				if ( scope.enablePan === false ) return;
+
+				panEnd.set( event.clientX, event.clientY );
+				panDelta.subVectors( panEnd, panStart );
+
+				pan( panDelta.x, panDelta.y );
+
+				panStart.copy( panEnd );
+
+			}
+
+			if ( state !== STATE.NONE ) scope.update();
+
+		}
+
+		function onMouseUp( /* event */ ) {
+
+			if ( scope.enabled === false ) return;
+
+			document.removeEventListener( 'mousemove', onMouseMove, false );
+			document.removeEventListener( 'mouseup', onMouseUp, false );
+			scope.dispatchEvent( endEvent );
+			state = STATE.NONE;
+
+		}
+
+		function onMouseWheel( event ) {
+
+			if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;
+
+			event.preventDefault();
+			event.stopPropagation();
+
+			var delta = 0;
+
+			if ( event.wheelDelta !== undefined ) {
+
+				// WebKit / Opera / Explorer 9
+
+				delta = event.wheelDelta;
+
+			} else if ( event.detail !== undefined ) {
+
+				// Firefox
+
+				delta = - event.detail;
+
+			}
+
+			if ( delta > 0 ) {
+
+				constraint.dollyOut( getZoomScale() );
+
+			} else if ( delta < 0 ) {
+
+				constraint.dollyIn( getZoomScale() );
+
+			}
+
+			scope.update();
+			scope.dispatchEvent( startEvent );
+			scope.dispatchEvent( endEvent );
+
+		}
+
+		function onKeyDown( event ) {
+
+			if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
+
+			switch ( event.keyCode ) {
+
+				case scope.keys.UP:
+					pan( 0, scope.keyPanSpeed );
+					scope.update();
+					break;
+
+				case scope.keys.BOTTOM:
+					pan( 0, - scope.keyPanSpeed );
+					scope.update();
+					break;
+
+				case scope.keys.LEFT:
+					pan( scope.keyPanSpeed, 0 );
+					scope.update();
+					break;
+
+				case scope.keys.RIGHT:
+					pan( - scope.keyPanSpeed, 0 );
+					scope.update();
+					break;
+
+			}
+
+		}
+
+		function touchstart( event ) {
+
+			if ( scope.enabled === false ) return;
+
+			switch ( event.touches.length ) {
+
+				case 1:	// one-fingered touch: rotate
+
+					if ( scope.enableRotate === false ) return;
+
+					state = STATE.TOUCH_ROTATE;
+
+					rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+					break;
+
+				case 2:	// two-fingered touch: dolly
+
+					if ( scope.enableZoom === false ) return;
+
+					state = STATE.TOUCH_DOLLY;
+
+					var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
+					var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
+					var distance = Math.sqrt( dx * dx + dy * dy );
+					dollyStart.set( 0, distance );
+					break;
+
+				case 3: // three-fingered touch: pan
+
+					if ( scope.enablePan === false ) return;
+
+					state = STATE.TOUCH_PAN;
+
+					panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+					break;
+
+				default:
+
+					state = STATE.NONE;
+
+			}
+
+			if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
+
+		}
+
+		function touchmove( event ) {
+
+			if ( scope.enabled === false ) return;
+
+			event.preventDefault();
+			event.stopPropagation();
+
+			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+			switch ( event.touches.length ) {
+
+				case 1: // one-fingered touch: rotate
+
+					if ( scope.enableRotate === false ) return;
+					if ( state !== STATE.TOUCH_ROTATE ) return;
+
+					rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+					rotateDelta.subVectors( rotateEnd, rotateStart );
+
+					// rotating across whole screen goes 360 degrees around
+					constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
+					// rotating up and down along whole screen attempts to go 360, but limited to 180
+					constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
+
+					rotateStart.copy( rotateEnd );
+
+					scope.update();
+					break;
+
+				case 2: // two-fingered touch: dolly
+
+					if ( scope.enableZoom === false ) return;
+					if ( state !== STATE.TOUCH_DOLLY ) return;
+
+					var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
+					var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
+					var distance = Math.sqrt( dx * dx + dy * dy );
+
+					dollyEnd.set( 0, distance );
+					dollyDelta.subVectors( dollyEnd, dollyStart );
+
+					if ( dollyDelta.y > 0 ) {
+
+						constraint.dollyOut( getZoomScale() );
+
+					} else if ( dollyDelta.y < 0 ) {
+
+						constraint.dollyIn( getZoomScale() );
+
+					}
+
+					dollyStart.copy( dollyEnd );
+
+					scope.update();
+					break;
+
+				case 3: // three-fingered touch: pan
+
+					if ( scope.enablePan === false ) return;
+					if ( state !== STATE.TOUCH_PAN ) return;
+
+					panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+					panDelta.subVectors( panEnd, panStart );
+
+					pan( panDelta.x, panDelta.y );
+
+					panStart.copy( panEnd );
+
+					scope.update();
+					break;
+
+				default:
+
+					state = STATE.NONE;
+
+			}
+
+		}
+
+		function touchend( /* event */ ) {
+
+			if ( scope.enabled === false ) return;
+
+			scope.dispatchEvent( endEvent );
+			state = STATE.NONE;
+
+		}
+
+		function contextmenu( event ) {
+
+			event.preventDefault();
+
+		}
+
+		this.dispose = function() {
+
+			this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
+			this.domElement.removeEventListener( 'mousedown', onMouseDown, false );
+			this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
+			this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+
+			this.domElement.removeEventListener( 'touchstart', touchstart, false );
+			this.domElement.removeEventListener( 'touchend', touchend, false );
+			this.domElement.removeEventListener( 'touchmove', touchmove, false );
+
+			document.removeEventListener( 'mousemove', onMouseMove, false );
+			document.removeEventListener( 'mouseup', onMouseUp, false );
+
+			window.removeEventListener( 'keydown', onKeyDown, false );
+
+		}
+
+		this.domElement.addEventListener( 'contextmenu', contextmenu, false );
+
+		this.domElement.addEventListener( 'mousedown', onMouseDown, false );
+		this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
+		this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+
+		this.domElement.addEventListener( 'touchstart', touchstart, false );
+		this.domElement.addEventListener( 'touchend', touchend, false );
+		this.domElement.addEventListener( 'touchmove', touchmove, false );
+
+		window.addEventListener( 'keydown', onKeyDown, false );
+
+		// force an update at start
+		this.update();
+
+	};
+
+	THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
+	THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
+
+	Object.defineProperties( THREE.OrbitControls.prototype, {
+
+		object: {
+
+			get: function () {
+
+				return this.constraint.object;
+
+			}
+
+		},
+
+		target: {
+
+			get: function () {
+
+				return this.constraint.target;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' );
+				this.constraint.target.copy( value );
+
+			}
+
+		},
+
+		minDistance : {
+
+			get: function () {
+
+				return this.constraint.minDistance;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.minDistance = value;
+
+			}
+
+		},
+
+		maxDistance : {
+
+			get: function () {
+
+				return this.constraint.maxDistance;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.maxDistance = value;
+
+			}
+
+		},
+
+		minZoom : {
+
+			get: function () {
+
+				return this.constraint.minZoom;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.minZoom = value;
+
+			}
+
+		},
+
+		maxZoom : {
+
+			get: function () {
+
+				return this.constraint.maxZoom;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.maxZoom = value;
+
+			}
+
+		},
+
+		minPolarAngle : {
+
+			get: function () {
+
+				return this.constraint.minPolarAngle;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.minPolarAngle = value;
+
+			}
+
+		},
+
+		maxPolarAngle : {
+
+			get: function () {
+
+				return this.constraint.maxPolarAngle;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.maxPolarAngle = value;
+
+			}
+
+		},
+
+		minAzimuthAngle : {
+
+			get: function () {
+
+				return this.constraint.minAzimuthAngle;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.minAzimuthAngle = value;
+
+			}
+
+		},
+
+		maxAzimuthAngle : {
+
+			get: function () {
+
+				return this.constraint.maxAzimuthAngle;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.maxAzimuthAngle = value;
+
+			}
+
+		},
+
+		enableDamping : {
+
+			get: function () {
+
+				return this.constraint.enableDamping;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.enableDamping = value;
+
+			}
+
+		},
+
+		dampingFactor : {
+
+			get: function () {
+
+				return this.constraint.dampingFactor;
+
+			},
+
+			set: function ( value ) {
+
+				this.constraint.dampingFactor = value;
+
+			}
+
+		},
+
+		// backward compatibility
+
+		noZoom: {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
+				return ! this.enableZoom;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
+				this.enableZoom = ! value;
+
+			}
+
+		},
+
+		noRotate: {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
+				return ! this.enableRotate;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
+				this.enableRotate = ! value;
+
+			}
+
+		},
+
+		noPan: {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
+				return ! this.enablePan;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
+				this.enablePan = ! value;
+
+			}
+
+		},
+
+		noKeys: {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
+				return ! this.enableKeys;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
+				this.enableKeys = ! value;
+
+			}
+
+		},
+
+		staticMoving : {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
+				return ! this.constraint.enableDamping;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
+				this.constraint.enableDamping = ! value;
+
+			}
+
+		},
+
+		dynamicDampingFactor : {
+
+			get: function () {
+
+				console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
+				return this.constraint.dampingFactor;
+
+			},
+
+			set: function ( value ) {
+
+				console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
+				this.constraint.dampingFactor = value;
+
+			}
+
+		}
+
+	} );
+
+}() );
diff --git a/emperor/support_files/vendor/js/three.js-plugins/Projector.js b/emperor/support_files/vendor/js/three.js-plugins/Projector.js
new file mode 100644
index 0000000..ac55d7a
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.js-plugins/Projector.js
@@ -0,0 +1,921 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author julianwa / https://github.com/julianwa
+ */
+
+THREE.RenderableObject = function () {
+
+	this.id = 0;
+
+	this.object = null;
+	this.z = 0;
+	this.renderOrder = 0;
+
+};
+
+//
+
+THREE.RenderableFace = function () {
+
+	this.id = 0;
+
+	this.v1 = new THREE.RenderableVertex();
+	this.v2 = new THREE.RenderableVertex();
+	this.v3 = new THREE.RenderableVertex();
+
+	this.normalModel = new THREE.Vector3();
+
+	this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
+	this.vertexNormalsLength = 0;
+
+	this.color = new THREE.Color();
+	this.material = null;
+	this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
+
+	this.z = 0;
+	this.renderOrder = 0;
+
+};
+
+//
+
+THREE.RenderableVertex = function () {
+
+	this.position = new THREE.Vector3();
+	this.positionWorld = new THREE.Vector3();
+	this.positionScreen = new THREE.Vector4();
+
+	this.visible = true;
+
+};
+
+THREE.RenderableVertex.prototype.copy = function ( vertex ) {
+
+	this.positionWorld.copy( vertex.positionWorld );
+	this.positionScreen.copy( vertex.positionScreen );
+
+};
+
+//
+
+THREE.RenderableLine = function () {
+
+	this.id = 0;
+
+	this.v1 = new THREE.RenderableVertex();
+	this.v2 = new THREE.RenderableVertex();
+
+	this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
+	this.material = null;
+
+	this.z = 0;
+	this.renderOrder = 0;
+
+};
+
+//
+
+THREE.RenderableSprite = function () {
+
+	this.id = 0;
+
+	this.object = null;
+
+	this.x = 0;
+	this.y = 0;
+	this.z = 0;
+
+	this.rotation = 0;
+	this.scale = new THREE.Vector2();
+
+	this.material = null;
+	this.renderOrder = 0;
+
+};
+
+//
+
+THREE.Projector = function () {
+
+	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
+	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
+	_face, _faceCount, _facePool = [], _facePoolLength = 0,
+	_line, _lineCount, _linePool = [], _linePoolLength = 0,
+	_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
+
+	_renderData = { objects: [], lights: [], elements: [] },
+
+	_vector3 = new THREE.Vector3(),
+	_vector4 = new THREE.Vector4(),
+
+	_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
+	_boundingBox = new THREE.Box3(),
+	_points3 = new Array( 3 ),
+	_points4 = new Array( 4 ),
+
+	_viewMatrix = new THREE.Matrix4(),
+	_viewProjectionMatrix = new THREE.Matrix4(),
+
+	_modelMatrix,
+	_modelViewProjectionMatrix = new THREE.Matrix4(),
+
+	_normalMatrix = new THREE.Matrix3(),
+
+	_frustum = new THREE.Frustum(),
+
+	_clippedVertex1PositionScreen = new THREE.Vector4(),
+	_clippedVertex2PositionScreen = new THREE.Vector4();
+
+	//
+
+	this.projectVector = function ( vector, camera ) {
+
+		console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
+		vector.project( camera );
+
+	};
+
+	this.unprojectVector = function ( vector, camera ) {
+
+		console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
+		vector.unproject( camera );
+
+	};
+
+	this.pickingRay = function ( vector, camera ) {
+
+		console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
+
+	};
+
+	//
+
+	var RenderList = function () {
+
+		var normals = [];
+		var uvs = [];
+
+		var object = null;
+		var material = null;
+
+		var normalMatrix = new THREE.Matrix3();
+
+		var setObject = function ( value ) {
+
+			object = value;
+			material = object.material;
+
+			normalMatrix.getNormalMatrix( object.matrixWorld );
+
+			normals.length = 0;
+			uvs.length = 0;
+
+		};
+
+		var projectVertex = function ( vertex ) {
+
+			var position = vertex.position;
+			var positionWorld = vertex.positionWorld;
+			var positionScreen = vertex.positionScreen;
+
+			positionWorld.copy( position ).applyMatrix4( _modelMatrix );
+			positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
+
+			var invW = 1 / positionScreen.w;
+
+			positionScreen.x *= invW;
+			positionScreen.y *= invW;
+			positionScreen.z *= invW;
+
+			vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
+					 positionScreen.y >= - 1 && positionScreen.y <= 1 &&
+					 positionScreen.z >= - 1 && positionScreen.z <= 1;
+
+		};
+
+		var pushVertex = function ( x, y, z ) {
+
+			_vertex = getNextVertexInPool();
+			_vertex.position.set( x, y, z );
+
+			projectVertex( _vertex );
+
+		};
+
+		var pushNormal = function ( x, y, z ) {
+
+			normals.push( x, y, z );
+
+		};
+
+		var pushUv = function ( x, y ) {
+
+			uvs.push( x, y );
+
+		};
+
+		var checkTriangleVisibility = function ( v1, v2, v3 ) {
+
+			if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
+
+			_points3[ 0 ] = v1.positionScreen;
+			_points3[ 1 ] = v2.positionScreen;
+			_points3[ 2 ] = v3.positionScreen;
+
+			return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) );
+
+		};
+
+		var checkBackfaceCulling = function ( v1, v2, v3 ) {
+
+			return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
+				    ( v2.positionScreen.y - v1.positionScreen.y ) -
+				    ( v3.positionScreen.y - v1.positionScreen.y ) *
+				    ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
+
+		};
+
+		var pushLine = function ( a, b ) {
+
+			var v1 = _vertexPool[ a ];
+			var v2 = _vertexPool[ b ];
+
+			_line = getNextLineInPool();
+
+			_line.id = object.id;
+			_line.v1.copy( v1 );
+			_line.v2.copy( v2 );
+			_line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
+			_line.renderOrder = object.renderOrder;
+
+			_line.material = object.material;
+
+			_renderData.elements.push( _line );
+
+		};
+
+		var pushTriangle = function ( a, b, c ) {
+
+			var v1 = _vertexPool[ a ];
+			var v2 = _vertexPool[ b ];
+			var v3 = _vertexPool[ c ];
+
+			if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
+
+			if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
+
+				_face = getNextFaceInPool();
+
+				_face.id = object.id;
+				_face.v1.copy( v1 );
+				_face.v2.copy( v2 );
+				_face.v3.copy( v3 );
+				_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
+				_face.renderOrder = object.renderOrder;
+
+				// use first vertex normal as face normal
+
+				_face.normalModel.fromArray( normals, a * 3 );
+				_face.normalModel.applyMatrix3( normalMatrix ).normalize();
+
+				for ( var i = 0; i < 3; i ++ ) {
+
+					var normal = _face.vertexNormalsModel[ i ];
+					normal.fromArray( normals, arguments[ i ] * 3 );
+					normal.applyMatrix3( normalMatrix ).normalize();
+
+					var uv = _face.uvs[ i ];
+					uv.fromArray( uvs, arguments[ i ] * 2 );
+
+				}
+
+				_face.vertexNormalsLength = 3;
+
+				_face.material = object.material;
+
+				_renderData.elements.push( _face );
+
+			}
+
+		};
+
+		return {
+			setObject: setObject,
+			projectVertex: projectVertex,
+			checkTriangleVisibility: checkTriangleVisibility,
+			checkBackfaceCulling: checkBackfaceCulling,
+			pushVertex: pushVertex,
+			pushNormal: pushNormal,
+			pushUv: pushUv,
+			pushLine: pushLine,
+			pushTriangle: pushTriangle
+		}
+
+	};
+
+	var renderList = new RenderList();
+
+	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
+
+		_faceCount = 0;
+		_lineCount = 0;
+		_spriteCount = 0;
+
+		_renderData.elements.length = 0;
+
+		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
+		if ( camera.parent === null ) camera.updateMatrixWorld();
+
+		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
+		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
+
+		_frustum.setFromMatrix( _viewProjectionMatrix );
+
+		//
+
+		_objectCount = 0;
+
+		_renderData.objects.length = 0;
+		_renderData.lights.length = 0;
+
+		scene.traverseVisible( function ( object ) {
+
+			if ( object instanceof THREE.Light ) {
+
+				_renderData.lights.push( object );
+
+			} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
+
+				var material = object.material;
+
+				if ( material.visible === false ) return;
+
+				if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
+
+					_object = getNextObjectInPool();
+					_object.id = object.id;
+					_object.object = object;
+
+					_vector3.setFromMatrixPosition( object.matrixWorld );
+					_vector3.applyProjection( _viewProjectionMatrix );
+					_object.z = _vector3.z;
+					_object.renderOrder = object.renderOrder;
+
+					_renderData.objects.push( _object );
+
+				}
+
+			}
+
+		} );
+
+		if ( sortObjects === true ) {
+
+			_renderData.objects.sort( painterSort );
+
+		}
+
+		//
+
+		for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
+
+			var object = _renderData.objects[ o ].object;
+			var geometry = object.geometry;
+
+			renderList.setObject( object );
+
+			_modelMatrix = object.matrixWorld;
+
+			_vertexCount = 0;
+
+			if ( object instanceof THREE.Mesh ) {
+
+				if ( geometry instanceof THREE.BufferGeometry ) {
+
+					var attributes = geometry.attributes;
+					var groups = geometry.groups;
+
+					if ( attributes.position === undefined ) continue;
+
+					var positions = attributes.position.array;
+
+					for ( var i = 0, l = positions.length; i < l; i += 3 ) {
+
+						renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+
+					}
+
+					if ( attributes.normal !== undefined ) {
+
+						var normals = attributes.normal.array;
+
+						for ( var i = 0, l = normals.length; i < l; i += 3 ) {
+
+							renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
+
+						}
+
+					}
+
+					if ( attributes.uv !== undefined ) {
+
+						var uvs = attributes.uv.array;
+
+						for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
+
+							renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
+
+						}
+
+					}
+
+					if ( geometry.index !== null ) {
+
+						var indices = geometry.index.array;
+
+						if ( groups.length > 0 ) {
+
+							for ( var o = 0; o < groups.length; o ++ ) {
+
+								var group = groups[ o ];
+
+								for ( var i = group.start, l = group.start + group.count; i < l; i += 3 ) {
+
+									renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
+
+								}
+
+							}
+
+						} else {
+
+							for ( var i = 0, l = indices.length; i < l; i += 3 ) {
+
+								renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
+
+							}
+
+						}
+
+					} else {
+
+						for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
+
+							renderList.pushTriangle( i, i + 1, i + 2 );
+
+						}
+
+					}
+
+				} else if ( geometry instanceof THREE.Geometry ) {
+
+					var vertices = geometry.vertices;
+					var faces = geometry.faces;
+					var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
+
+					_normalMatrix.getNormalMatrix( _modelMatrix );
+
+					var material = object.material;
+
+					var isFaceMaterial = material instanceof THREE.MeshFaceMaterial;
+					var objectMaterials = isFaceMaterial === true ? object.material : null;
+
+					for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
+
+						var vertex = vertices[ v ];
+
+						_vector3.copy( vertex );
+
+						if ( material.morphTargets === true ) {
+
+							var morphTargets = geometry.morphTargets;
+							var morphInfluences = object.morphTargetInfluences;
+
+							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
+
+								var influence = morphInfluences[ t ];
+
+								if ( influence === 0 ) continue;
+
+								var target = morphTargets[ t ];
+								var targetVertex = target.vertices[ v ];
+
+								_vector3.x += ( targetVertex.x - vertex.x ) * influence;
+								_vector3.y += ( targetVertex.y - vertex.y ) * influence;
+								_vector3.z += ( targetVertex.z - vertex.z ) * influence;
+
+							}
+
+						}
+
+						renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );
+
+					}
+
+					for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
+
+						var face = faces[ f ];
+
+						material = isFaceMaterial === true
+							 ? objectMaterials.materials[ face.materialIndex ]
+							 : object.material;
+
+						if ( material === undefined ) continue;
+
+						var side = material.side;
+
+						var v1 = _vertexPool[ face.a ];
+						var v2 = _vertexPool[ face.b ];
+						var v3 = _vertexPool[ face.c ];
+
+						if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
+
+						var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
+
+						if ( side !== THREE.DoubleSide ) {
+
+							if ( side === THREE.FrontSide && visible === false ) continue;
+							if ( side === THREE.BackSide && visible === true ) continue;
+
+						}
+
+						_face = getNextFaceInPool();
+
+						_face.id = object.id;
+						_face.v1.copy( v1 );
+						_face.v2.copy( v2 );
+						_face.v3.copy( v3 );
+
+						_face.normalModel.copy( face.normal );
+
+						if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
+
+							_face.normalModel.negate();
+
+						}
+
+						_face.normalModel.applyMatrix3( _normalMatrix ).normalize();
+
+						var faceVertexNormals = face.vertexNormals;
+
+						for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
+
+							var normalModel = _face.vertexNormalsModel[ n ];
+							normalModel.copy( faceVertexNormals[ n ] );
+
+							if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
+
+								normalModel.negate();
+
+							}
+
+							normalModel.applyMatrix3( _normalMatrix ).normalize();
+
+						}
+
+						_face.vertexNormalsLength = faceVertexNormals.length;
+
+						var vertexUvs = faceVertexUvs[ f ];
+
+						if ( vertexUvs !== undefined ) {
+
+							for ( var u = 0; u < 3; u ++ ) {
+
+								_face.uvs[ u ].copy( vertexUvs[ u ] );
+
+							}
+
+						}
+
+						_face.color = face.color;
+						_face.material = material;
+
+						_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
+						_face.renderOrder = object.renderOrder;
+
+						_renderData.elements.push( _face );
+
+					}
+
+				}
+
+			} else if ( object instanceof THREE.Line ) {
+
+				if ( geometry instanceof THREE.BufferGeometry ) {
+
+					var attributes = geometry.attributes;
+
+					if ( attributes.position !== undefined ) {
+
+						var positions = attributes.position.array;
+
+						for ( var i = 0, l = positions.length; i < l; i += 3 ) {
+
+							renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+
+						}
+
+						if ( geometry.index !== null ) {
+
+							var indices = geometry.index.array;
+
+							for ( var i = 0, l = indices.length; i < l; i += 2 ) {
+
+								renderList.pushLine( indices[ i ], indices[ i + 1 ] );
+
+							}
+
+						} else {
+
+							var step = object instanceof THREE.LineSegments ? 2 : 1;
+
+							for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
+
+								renderList.pushLine( i, i + 1 );
+
+							}
+
+						}
+
+					}
+
+				} else if ( geometry instanceof THREE.Geometry ) {
+
+					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
+
+					var vertices = object.geometry.vertices;
+
+					if ( vertices.length === 0 ) continue;
+
+					v1 = getNextVertexInPool();
+					v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
+
+					var step = object instanceof THREE.LineSegments ? 2 : 1;
+
+					for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
+
+						v1 = getNextVertexInPool();
+						v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
+
+						if ( ( v + 1 ) % step > 0 ) continue;
+
+						v2 = _vertexPool[ _vertexCount - 2 ];
+
+						_clippedVertex1PositionScreen.copy( v1.positionScreen );
+						_clippedVertex2PositionScreen.copy( v2.positionScreen );
+
+						if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
+
+							// Perform the perspective divide
+							_clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
+							_clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
+
+							_line = getNextLineInPool();
+
+							_line.id = object.id;
+							_line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
+							_line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
+
+							_line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
+							_line.renderOrder = object.renderOrder;
+
+							_line.material = object.material;
+
+							if ( object.material.vertexColors === THREE.VertexColors ) {
+
+								_line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
+								_line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
+
+							}
+
+							_renderData.elements.push( _line );
+
+						}
+
+					}
+
+				}
+
+			} else if ( object instanceof THREE.Sprite ) {
+
+				_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
+				_vector4.applyMatrix4( _viewProjectionMatrix );
+
+				var invW = 1 / _vector4.w;
+
+				_vector4.z *= invW;
+
+				if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
+
+					_sprite = getNextSpriteInPool();
+					_sprite.id = object.id;
+					_sprite.x = _vector4.x * invW;
+					_sprite.y = _vector4.y * invW;
+					_sprite.z = _vector4.z;
+					_sprite.renderOrder = object.renderOrder;
+					_sprite.object = object;
+
+					_sprite.rotation = object.rotation;
+
+					_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
+					_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
+
+					_sprite.material = object.material;
+
+					_renderData.elements.push( _sprite );
+
+				}
+
+			}
+
+		}
+
+		if ( sortElements === true ) {
+
+			_renderData.elements.sort( painterSort );
+
+		}
+
+		return _renderData;
+
+	};
+
+	// Pools
+
+	function getNextObjectInPool() {
+
+		if ( _objectCount === _objectPoolLength ) {
+
+			var object = new THREE.RenderableObject();
+			_objectPool.push( object );
+			_objectPoolLength ++;
+			_objectCount ++;
+			return object;
+
+		}
+
+		return _objectPool[ _objectCount ++ ];
+
+	}
+
+	function getNextVertexInPool() {
+
+		if ( _vertexCount === _vertexPoolLength ) {
+
+			var vertex = new THREE.RenderableVertex();
+			_vertexPool.push( vertex );
+			_vertexPoolLength ++;
+			_vertexCount ++;
+			return vertex;
+
+		}
+
+		return _vertexPool[ _vertexCount ++ ];
+
+	}
+
+	function getNextFaceInPool() {
+
+		if ( _faceCount === _facePoolLength ) {
+
+			var face = new THREE.RenderableFace();
+			_facePool.push( face );
+			_facePoolLength ++;
+			_faceCount ++;
+			return face;
+
+		}
+
+		return _facePool[ _faceCount ++ ];
+
+
+	}
+
+	function getNextLineInPool() {
+
+		if ( _lineCount === _linePoolLength ) {
+
+			var line = new THREE.RenderableLine();
+			_linePool.push( line );
+			_linePoolLength ++;
+			_lineCount ++;
+			return line;
+
+		}
+
+		return _linePool[ _lineCount ++ ];
+
+	}
+
+	function getNextSpriteInPool() {
+
+		if ( _spriteCount === _spritePoolLength ) {
+
+			var sprite = new THREE.RenderableSprite();
+			_spritePool.push( sprite );
+			_spritePoolLength ++;
+			_spriteCount ++;
+			return sprite;
+
+		}
+
+		return _spritePool[ _spriteCount ++ ];
+
+	}
+
+	//
+
+	function painterSort( a, b ) {
+
+		if ( a.renderOrder !== b.renderOrder ) {
+
+			return a.renderOrder - b.renderOrder;
+
+		} else if ( a.z !== b.z ) {
+
+			return b.z - a.z;
+
+		} else if ( a.id !== b.id ) {
+
+			return a.id - b.id;
+
+		} else {
+
+			return 0;
+
+		}
+
+	}
+
+	function clipLine( s1, s2 ) {
+
+		var alpha1 = 0, alpha2 = 1,
+
+		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
+		// Z = -1 and Z = +1, respectively.
+		bc1near =  s1.z + s1.w,
+		bc2near =  s2.z + s2.w,
+		bc1far =  - s1.z + s1.w,
+		bc2far =  - s2.z + s2.w;
+
+		if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
+
+			// Both vertices lie entirely within all clip planes.
+			return true;
+
+		} else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
+
+			// Both vertices lie entirely outside one of the clip planes.
+			return false;
+
+		} else {
+
+			// The line segment spans at least one clip plane.
+
+			if ( bc1near < 0 ) {
+
+				// v1 lies outside the near plane, v2 inside
+				alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
+
+			} else if ( bc2near < 0 ) {
+
+				// v2 lies outside the near plane, v1 inside
+				alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
+
+			}
+
+			if ( bc1far < 0 ) {
+
+				// v1 lies outside the far plane, v2 inside
+				alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
+
+			} else if ( bc2far < 0 ) {
+
+				// v2 lies outside the far plane, v2 inside
+				alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
+
+			}
+
+			if ( alpha2 < alpha1 ) {
+
+				// The line segment spans two boundaries, but is outside both of them.
+				// (This can't happen when we're only clipping against just near/far but good
+				//  to leave the check here for future usage if other clip planes are added.)
+				return false;
+
+			} else {
+
+				// Update the s1 and s2 vertices to match the clipped line segment.
+				s1.lerp( s2, alpha1 );
+				s2.lerp( s1, 1 - alpha2 );
+
+				return true;
+
+			}
+
+		}
+
+	}
+
+};
diff --git a/emperor/support_files/vendor/js/three.js-plugins/SVGRenderer.js b/emperor/support_files/vendor/js/three.js-plugins/SVGRenderer.js
new file mode 100644
index 0000000..b2328b8
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.js-plugins/SVGRenderer.js
@@ -0,0 +1,519 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ *
+ * This modified version has a two new methods: renderText and getTextNode,
+ * which allows us to insert text to the SVG renderer. The text has to be
+ * created using sprites and have the attribute text. 
+ */
+
+THREE.SVGObject = function ( node ) {
+
+	THREE.Object3D.call( this );
+
+	this.node = node;
+
+};
+
+THREE.SVGObject.prototype = Object.create( THREE.Object3D.prototype );
+THREE.SVGObject.prototype.constructor = THREE.SVGObject;
+
+THREE.SVGRenderer = function () {
+
+	console.log( 'THREE.SVGRenderer', THREE.REVISION );
+
+	var _this = this,
+	_renderData, _elements, _lights,
+	_projector = new THREE.Projector(),
+	_svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' ),
+	_svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf,
+
+	_v1, _v2, _v3, _v4,
+
+	_clipBox = new THREE.Box2(),
+	_elemBox = new THREE.Box2(),
+
+	_color = new THREE.Color(),
+	_diffuseColor = new THREE.Color(),
+	_ambientLight = new THREE.Color(),
+	_directionalLights = new THREE.Color(),
+	_pointLights = new THREE.Color(),
+	_clearColor = new THREE.Color(),
+	_clearAlpha = 1,
+
+	_vector3 = new THREE.Vector3(), // Needed for PointLight
+	_centroid = new THREE.Vector3(),
+	_normal = new THREE.Vector3(),
+	_normalViewMatrix = new THREE.Matrix3(),
+
+	_viewMatrix = new THREE.Matrix4(),
+	_viewProjectionMatrix = new THREE.Matrix4(),
+
+	_svgPathPool = [], _svgLinePool = [], _svgRectPool = [], _svgTextPool = [],
+	_svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0,
+	_quality = 1;
+
+	this.domElement = _svg;
+
+	this.autoClear = true;
+	this.sortObjects = true;
+	this.sortElements = true;
+
+	this.info = {
+
+		render: {
+
+			vertices: 0,
+			faces: 0
+
+		}
+
+	};
+
+	this.setQuality = function( quality ) {
+
+		switch ( quality ) {
+
+			case "high": _quality = 1; break;
+			case "low": _quality = 0; break;
+
+		}
+
+	};
+
+	// WebGLRenderer compatibility
+
+	this.supportsVertexTextures = function () {};
+	this.setFaceCulling = function () {};
+
+	this.setClearColor = function ( color, alpha ) {
+
+		_clearColor.set( color );
+		_clearAlpha = alpha !== undefined ? alpha : 1;
+
+	};
+
+	this.setPixelRatio = function () {};
+
+	this.setSize = function( width, height ) {
+
+		_svgWidth = width; _svgHeight = height;
+		_svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2;
+
+		_svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight );
+		_svg.setAttribute( 'width', _svgWidth );
+		_svg.setAttribute( 'height', _svgHeight );
+
+		_clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf );
+		_clipBox.max.set( _svgWidthHalf, _svgHeightHalf );
+
+	};
+
+	this.clear = function () {
+
+		_pathCount = 0;
+		_lineCount = 0;
+		_rectCount = 0;
+
+		while ( _svg.childNodes.length > 0 ) {
+
+			_svg.removeChild( _svg.childNodes[ 0 ] );
+
+		}
+
+		_svg.style.backgroundColor = 'rgba(' + ( ( _clearColor.r * 255 ) | 0 ) + ',' + ( ( _clearColor.g * 255 ) | 0 ) + ',' + ( ( _clearColor.b * 255 ) | 0 ) + ',' + _clearAlpha + ')';
+
+	};
+
+	this.render = function ( scene, camera ) {
+
+		if ( camera instanceof THREE.Camera === false ) {
+
+			console.error( 'THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.' );
+			return;
+
+		}
+
+		if ( this.autoClear === true ) this.clear();
+
+		_this.info.render.vertices = 0;
+		_this.info.render.faces = 0;
+
+		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
+		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
+
+		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
+		_elements = _renderData.elements;
+		_lights = _renderData.lights;
+
+		_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
+
+		calculateLights( _lights );
+
+		for ( var e = 0, el = _elements.length; e < el; e ++ ) {
+
+			var element = _elements[ e ];
+			var material = element.material;
+
+			if ( material === undefined || material.opacity === 0 ) continue;
+
+			_elemBox.makeEmpty();
+
+			if ( element instanceof THREE.RenderableSprite ) {
+
+				_v1 = element;
+				_v1.x *= _svgWidthHalf; _v1.y *= - _svgHeightHalf;
+
+				if ('text' in element.object) {
+
+					renderText( _v1, element, material );
+
+				} else {
+
+					renderSprite( _v1, element, material );
+
+				}
+
+			} else if ( element instanceof THREE.RenderableLine ) {
+
+				_v1 = element.v1; _v2 = element.v2;
+
+				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
+				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
+
+				_elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] );
+
+				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
+
+					renderLine( _v1, _v2, element, material );
+
+				}
+
+			} else if ( element instanceof THREE.RenderableFace ) {
+
+				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
+
+				if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
+				if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
+				if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
+
+				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
+				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
+				_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf;
+
+				_elemBox.setFromPoints( [
+					_v1.positionScreen,
+					_v2.positionScreen,
+					_v3.positionScreen
+				] );
+
+				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
+
+					renderFace3( _v1, _v2, _v3, element, material );
+
+				}
+
+			}
+
+		}
+
+		scene.traverseVisible( function ( object ) {
+
+			 if ( object instanceof THREE.SVGObject ) {
+
+				_vector3.setFromMatrixPosition( object.matrixWorld );
+				_vector3.applyProjection( _viewProjectionMatrix );
+
+				var x =   _vector3.x * _svgWidthHalf;
+				var y = - _vector3.y * _svgHeightHalf;
+
+				var node = object.node;
+				node.setAttribute( 'transform', 'translate(' + x + ',' + y + ')' );
+
+				_svg.appendChild( node );
+
+			}
+
+		} );
+
+	};
+
+	function calculateLights( lights ) {
+
+		_ambientLight.setRGB( 0, 0, 0 );
+		_directionalLights.setRGB( 0, 0, 0 );
+		_pointLights.setRGB( 0, 0, 0 );
+
+		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
+
+			var light = lights[ l ];
+			var lightColor = light.color;
+
+			if ( light instanceof THREE.AmbientLight ) {
+
+				_ambientLight.r += lightColor.r;
+				_ambientLight.g += lightColor.g;
+				_ambientLight.b += lightColor.b;
+
+			} else if ( light instanceof THREE.DirectionalLight ) {
+
+				_directionalLights.r += lightColor.r;
+				_directionalLights.g += lightColor.g;
+				_directionalLights.b += lightColor.b;
+
+			} else if ( light instanceof THREE.PointLight ) {
+
+				_pointLights.r += lightColor.r;
+				_pointLights.g += lightColor.g;
+				_pointLights.b += lightColor.b;
+
+			}
+
+		}
+
+	}
+
+	function calculateLight( lights, position, normal, color ) {
+
+		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
+
+			var light = lights[ l ];
+			var lightColor = light.color;
+
+			if ( light instanceof THREE.DirectionalLight ) {
+
+				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
+
+				var amount = normal.dot( lightPosition );
+
+				if ( amount <= 0 ) continue;
+
+				amount *= light.intensity;
+
+				color.r += lightColor.r * amount;
+				color.g += lightColor.g * amount;
+				color.b += lightColor.b * amount;
+
+			} else if ( light instanceof THREE.PointLight ) {
+
+				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
+
+				var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
+
+				if ( amount <= 0 ) continue;
+
+				amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
+
+				if ( amount == 0 ) continue;
+
+				amount *= light.intensity;
+
+				color.r += lightColor.r * amount;
+				color.g += lightColor.g * amount;
+				color.b += lightColor.b * amount;
+
+			}
+
+		}
+
+	}
+
+	function renderSprite( v1, element, material ) {
+
+		var scaleX = element.scale.x * _svgWidthHalf;
+		var scaleY = element.scale.y * _svgHeightHalf;
+
+		_svgNode = getRectNode( _rectCount ++ );
+
+		_svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) );
+		_svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) );
+		_svgNode.setAttribute( 'width', scaleX );
+		_svgNode.setAttribute( 'height', scaleY );
+
+		if ( material instanceof THREE.SpriteMaterial ) {
+
+			_svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() );
+
+		}
+
+		_svg.appendChild( _svgNode );
+
+	}
+
+	function renderText( v1, element, material ) {
+
+		var scaleX = element.scale.x * _svgWidthHalf;
+		var scaleY = element.scale.y * _svgHeightHalf;
+		var scaleZ = element.scale.y * _svgHeightHalf;
+
+		_svgNode = getTextNode( _rectCount ++ );
+
+		_svgNode.setAttribute( 'x', v1.x );
+		_svgNode.setAttribute( 'y', v1.y );
+		_svgNode.setAttribute( 'z', v1.z );
+		_svgNode.setAttribute( 'font-family', 'Verdana' );
+		_svgNode.setAttribute( 'font-size', parseInt( _svgWidthHalf / 40 ) );
+		_svgNode.setAttribute( 'fill',  material.color.getStyle() );
+		_svgNode.textContent = element.object.text;
+
+ 		_svg.appendChild( _svgNode );
+
+	}
+
+	function renderLine( v1, v2, element, material ) {
+
+		_svgNode = getLineNode( _lineCount ++ );
+
+		_svgNode.setAttribute( 'x1', v1.positionScreen.x );
+		_svgNode.setAttribute( 'y1', v1.positionScreen.y );
+		_svgNode.setAttribute( 'x2', v2.positionScreen.x );
+		_svgNode.setAttribute( 'y2', v2.positionScreen.y );
+
+		if ( material instanceof THREE.LineBasicMaterial ) {
+
+			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );
+
+			_svg.appendChild( _svgNode );
+
+		}
+
+	}
+
+	function renderFace3( v1, v2, v3, element, material ) {
+
+		_this.info.render.vertices += 3;
+		_this.info.render.faces ++;
+
+		_svgNode = getPathNode( _pathCount ++ );
+		_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );
+
+		if ( material instanceof THREE.MeshBasicMaterial ) {
+
+			_color.copy( material.color );
+
+			if ( material.vertexColors === THREE.FaceColors ) {
+
+				_color.multiply( element.color );
+
+			}
+
+		} else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
+
+			_diffuseColor.copy( material.color );
+
+			if ( material.vertexColors === THREE.FaceColors ) {
+
+				_diffuseColor.multiply( element.color );
+
+			}
+
+			_color.copy( _ambientLight );
+
+			_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
+
+			calculateLight( _lights, _centroid, element.normalModel, _color );
+
+			_color.multiply( _diffuseColor ).add( material.emissive );
+
+		} else if ( material instanceof THREE.MeshNormalMaterial ) {
+
+			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
+
+			_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
+
+		}
+
+		if ( material.wireframe ) {
+
+			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );
+
+		} else {
+
+			_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );
+
+		}
+
+		_svg.appendChild( _svgNode );
+
+	}
+
+	function getLineNode( id ) {
+
+		if ( _svgLinePool[ id ] == null ) {
+
+			_svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );
+
+			if ( _quality == 0 ) {
+
+				_svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
+
+			}
+
+			return _svgLinePool[ id ];
+
+		}
+
+		return _svgLinePool[ id ];
+
+	}
+
+	function getPathNode( id ) {
+
+		if ( _svgPathPool[ id ] == null ) {
+
+			_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
+
+			if ( _quality == 0 ) {
+
+				_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
+
+			}
+
+			return _svgPathPool[ id ];
+
+		}
+
+		return _svgPathPool[ id ];
+
+	}
+
+	function getRectNode( id ) {
+
+		if ( _svgRectPool[ id ] == null ) {
+
+			_svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );
+
+			if ( _quality == 0 ) {
+
+				_svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
+
+			}
+
+			return _svgRectPool[ id ];
+
+		}
+
+		return _svgRectPool[ id ];
+
+	}
+
+	function getTextNode( id ) {
+
+		if ( _svgTextPool[ id ] == null ) {
+
+			_svgTextPool[ id ] = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+
+			if ( _quality == 0 ) {
+
+				_svgTextPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
+
+			}
+
+			return _svgTextPool[ id ];
+
+		}
+
+		return _svgTextPool[ id ];
+
+	}
+
+};
diff --git a/emperor/support_files/vendor/js/three.min.js b/emperor/support_files/vendor/js/three.min.js
new file mode 100644
index 0000000..bd820fe
--- /dev/null
+++ b/emperor/support_files/vendor/js/three.min.js
@@ -0,0 +1,870 @@
+// threejs.org/license
+'use strict';var THREE={REVISION:"73"};"function"===typeof define&&define.amd?define("three",THREE):"undefined"!==typeof exports&&"undefined"!==typeof module&&(module.exports=THREE);
+void 0!==self.requestAnimationFrame&&void 0!==self.cancelAnimationFrame||function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c<b.length&&!self.requestAnimationFrame;++c)self.requestAnimationFrame=self[b[c]+"RequestAnimationFrame"],self.cancelAnimationFrame=self[b[c]+"CancelAnimationFrame"]||self[b[c]+"CancelRequestAnimationFrame"];void 0===self.requestAnimationFrame&&void 0!==self.setTimeout&&(self.requestAnimationFrame=function(b){var c=Date.now(),g=Math.max(0,16-(c-a)),f=self.setTim [...]
+g)},g);a=c+g;return f});void 0===self.cancelAnimationFrame&&void 0!==self.clearTimeout&&(self.cancelAnimationFrame=function(a){self.clearTimeout(a)})}();void 0===self.performance&&(self.performance={});void 0===self.performance.now&&function(){var a=Date.now();self.performance.now=function(){return Date.now()-a}}();void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52));void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0<a?1:+a});
+void 0===Function.prototype.name&&void 0!==Object.defineProperty&&Object.defineProperty(Function.prototype,"name",{get:function(){return this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1]}});THREE.MOUSE={LEFT:0,MIDDLE:1,RIGHT:2};THREE.CullFaceNone=0;THREE.CullFaceBack=1;THREE.CullFaceFront=2;THREE.CullFaceFrontBack=3;THREE.FrontFaceDirectionCW=0;THREE.FrontFaceDirectionCCW=1;THREE.BasicShadowMap=0;THREE.PCFShadowMap=1;THREE.PCFSoftShadowMap=2;THREE.FrontSide=0;THREE.BackSide=1;
+THREE.DoubleSide=2;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NoBlending=0;THREE.NormalBlending=1;THREE.AdditiveBlending=2;THREE.SubtractiveBlending=3;THREE.MultiplyBlending=4;THREE.CustomBlending=5;THREE.AddEquation=100;THREE.SubtractEquation=101;THREE.ReverseSubtractEquation=102;THREE.MinEquation=103;THREE.MaxEquation=104;THREE.ZeroFactor=200;THREE.OneFactor=201;THREE.SrcColorFactor=202;THREE.OneMinusSrcColorFactor=203;
+THREE.SrcAlphaFactor=204;THREE.OneMinusSrcAlphaFactor=205;THREE.DstAlphaFactor=206;THREE.OneMinusDstAlphaFactor=207;THREE.DstColorFactor=208;THREE.OneMinusDstColorFactor=209;THREE.SrcAlphaSaturateFactor=210;THREE.NeverDepth=0;THREE.AlwaysDepth=1;THREE.LessDepth=2;THREE.LessEqualDepth=3;THREE.EqualDepth=4;THREE.GreaterEqualDepth=5;THREE.GreaterDepth=6;THREE.NotEqualDepth=7;THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.AddOperation=2;THREE.UVMapping=300;THREE.CubeReflectionMapping=301;
+THREE.CubeRefractionMapping=302;THREE.EquirectangularReflectionMapping=303;THREE.EquirectangularRefractionMapping=304;THREE.SphericalReflectionMapping=305;THREE.RepeatWrapping=1E3;THREE.ClampToEdgeWrapping=1001;THREE.MirroredRepeatWrapping=1002;THREE.NearestFilter=1003;THREE.NearestMipMapNearestFilter=1004;THREE.NearestMipMapLinearFilter=1005;THREE.LinearFilter=1006;THREE.LinearMipMapNearestFilter=1007;THREE.LinearMipMapLinearFilter=1008;THREE.UnsignedByteType=1009;THREE.ByteType=1010;
+THREE.ShortType=1011;THREE.UnsignedShortType=1012;THREE.IntType=1013;THREE.UnsignedIntType=1014;THREE.FloatType=1015;THREE.HalfFloatType=1025;THREE.UnsignedShort4444Type=1016;THREE.UnsignedShort5551Type=1017;THREE.UnsignedShort565Type=1018;THREE.AlphaFormat=1019;THREE.RGBFormat=1020;THREE.RGBAFormat=1021;THREE.LuminanceFormat=1022;THREE.LuminanceAlphaFormat=1023;THREE.RGBEFormat=THREE.RGBAFormat;THREE.RGB_S3TC_DXT1_Format=2001;THREE.RGBA_S3TC_DXT1_Format=2002;THREE.RGBA_S3TC_DXT3_Format=2003;
+THREE.RGBA_S3TC_DXT5_Format=2004;THREE.RGB_PVRTC_4BPPV1_Format=2100;THREE.RGB_PVRTC_2BPPV1_Format=2101;THREE.RGBA_PVRTC_4BPPV1_Format=2102;THREE.RGBA_PVRTC_2BPPV1_Format=2103;THREE.LoopOnce=2200;THREE.LoopRepeat=2201;THREE.LoopPingPong=2202;
+THREE.Projector=function(){console.error("THREE.Projector has been moved to /examples/js/renderers/Projector.js.");this.projectVector=function(a,b){console.warn("THREE.Projector: .projectVector() is now vector.project().");a.project(b)};this.unprojectVector=function(a,b){console.warn("THREE.Projector: .unprojectVector() is now vector.unproject().");a.unproject(b)};this.pickingRay=function(a,b){console.error("THREE.Projector: .pickingRay() is now raycaster.setFromCamera().")}};
+THREE.CanvasRenderer=function(){console.error("THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js");this.domElement=document.createElement("canvas");this.clear=function(){};this.render=function(){};this.setClearColor=function(){};this.setSize=function(){}};THREE.Color=function(a){return 3===arguments.length?this.fromArray(arguments):this.set(a)};
+THREE.Color.prototype={constructor:THREE.Color,r:1,g:1,b:1,set:function(a){a instanceof THREE.Color?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(){function a(a,c,d){0>d&&(d+=1);1<d&&(d-=1);return d<1/6?a+6*(c-a)*d:.5>d?c:d<2/3?a+6*(c-a)*(2/3-d):a} [...]
+c,d){b=THREE.Math.euclideanModulo(b,1);c=THREE.Math.clamp(c,0,1);d=THREE.Math.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c=.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s [...]
+Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){va [...]
+360,e=parseInt(c[2],10)/100,g=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,e,g)}}}else if(c=/^\#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0<a.length&&( [...]
+void 0!==c?this.setHex(c):console.warn("THREE.Color: Unknown color "+a));return this},clone:function(){return new this.constructor(this.r,this.g,this.b)},copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a,b){void 0===b&&(b=2);this.r=Math.pow(a.r,b);this.g=Math.pow(a.g,b);this.b=Math.pow(a.b,b);return this},copyLinearToGamma:function(a,b){void 0===b&&(b=2);var c=0<b?1/b:1;this.r=Math.pow(a.r,c);this.g=Math.pow(a.g,c);this.b=Math.pow(a.b,c);return t [...]
+this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),g=Math.min(b,c,d),f,h=(g+e)/2;if(g===e)g=f=0;else{var l=e-g,g=.5>= [...]
+l/(2-e-g);switch(e){case b:f=(c-d)/l+(c<d?6:0);break;case c:f=(d-b)/l+2;break;case d:f=(b-c)/l+4}f/=6}a.h=f;a.s=g;a.l=h;return a},getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},offsetHSL:function(a,b,c){var d=this.getHSL();d.h+=a;d.s+=b;d.l+=c;this.setHSL(d.h,d.s,d.l);return this},add:function(a){this.r+=a.r;this.g+=a.g;this.b+=a.b;return this},addColors:function(a,b){this.r=a.r+b.r;this.g=a.g+b.g;this.b=a.b+b.b;return this},addScalar:function( [...]
+a;this.g+=a;this.b+=a;return this},multiply:function(a){this.r*=a.r;this.g*=a.g;this.b*=a.b;return this},multiplyScalar:function(a){this.r*=a;this.g*=a;this.b*=a;return this},lerp:function(a,b){this.r+=(a.r-this.r)*b;this.g+=(a.g-this.g)*b;this.b+=(a.b-this.b)*b;return this},equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a,b){void 0===b&&(b=0);this.r=a[b];this.g=a[b+1];this.b=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&& [...]
+this.r;a[b+1]=this.g;a[b+2]=this.b;return a}};
+THREE.ColorKeywords={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:1243325 [...]
+darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greeny [...]
+grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,l [...]
+lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palego [...]
+palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal: [...]
+tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};THREE.Quaternion=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._w=void 0!==d?d:1};
+THREE.Quaternion.prototype={constructor:THREE.Quaternion,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get w(){return this._w},set w(a){this._w=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,thi [...]
+copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!1===a instanceof THREE.Euler)throw Error("THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var c=Math.cos(a._x/2),d=Math.cos(a._y/2),e=Math.cos(a._z/2),g=Math.sin(a._x/2),f=Math.sin(a._y/2),h=Math.sin(a._z/2),l=a.order;"XYZ"===l?(this._x=g*d*e+c*f*h,this._y=c*f*e-g*d*h,this._z=c*d*h+g*f*e,this._w=c*d*e-g*f*h) [...]
+l?(this._x=g*d*e+c*f*h,this._y=c*f*e-g*d*h,this._z=c*d*h-g*f*e,this._w=c*d*e+g*f*h):"ZXY"===l?(this._x=g*d*e-c*f*h,this._y=c*f*e+g*d*h,this._z=c*d*h+g*f*e,this._w=c*d*e-g*f*h):"ZYX"===l?(this._x=g*d*e-c*f*h,this._y=c*f*e+g*d*h,this._z=c*d*h-g*f*e,this._w=c*d*e+g*f*h):"YZX"===l?(this._x=g*d*e+c*f*h,this._y=c*f*e+g*d*h,this._z=c*d*h-g*f*e,this._w=c*d*e-g*f*h):"XZY"===l&&(this._x=g*d*e-c*f*h,this._y=c*f*e-g*d*h,this._z=c*d*h+g*f*e,this._w=c*d*e+g*f*h);if(!1!==b)this.onChangeCallback();retur [...]
+b){var c=b/2,d=Math.sin(c);this._x=a.x*d;this._y=a.y*d;this._z=a.z*d;this._w=Math.cos(c);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],g=b[5],f=b[9],h=b[2],l=b[6],b=b[10],k=c+g+b;0<k?(c=.5/Math.sqrt(k+1),this._w=.25/c,this._x=(l-f)*c,this._y=(d-h)*c,this._z=(e-a)*c):c>g&&c>b?(c=2*Math.sqrt(1+c-g-b),this._w=(l-f)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):g>b?(c=2*Math.sqrt(1+g-c-b),this._w=(d-h)/c,this._x=(a+ [...]
+.25*c,this._z=(f+l)/c):(c=2*Math.sqrt(1+b-c-g),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(f+l)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;this.normalize();return this}}(),inverse:function(){this.conjugate().normalize();return this},co [...]
+-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback( [...]
+multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,g=a._w,f=b._x,h=b._y,l=b._z,k=b._w;this._x=c*k+g*f+d*l-e*h;this._y=d*k+g*h+e*f-c*l;this._z=e*k+g*l+c*h-d*f;this._w=g*k-c*f-d*h-e*l;this.onChangeCallback();return this},multiplyVector3:function(a){console.war [...]
+return a.applyQuaternion(this)},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,g=this._w,f=g*a._w+c*a._x+d*a._y+e*a._z;0>f?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,f=-f):this.copy(a);if(1<=f)return this._w=g,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(f),l=Math.sqrt(1-f*f);if(.001>Math.abs(l))return this._w=.5*(g+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;f=Math.sin((1- [...]
+Math.sin(b*h)/l;this._w=g*f+this._w*h;this._x=c*f+this._x*h;this._y=d*f+this._y*h;this._z=e*f+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return  [...]
+a;return this},onChangeCallback:function(){}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0};
+THREE.Vector2.prototype={constructor:THREE.Vector2,get width(){return this.x},set width(a){this.x=a},get height(){return this.y},set height(a){this.y=a},set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;de [...]
+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+ [...]
+sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){isFinite(a)?(this.x*=a,this.y*=a):this.y=this.x=0;return this},divide:function(a){thi [...]
+this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set [...]
+b)}}(),clampLength:function(a,b){var c=this.length();this.multiplyScalar(Math.max(a,Math.min(b,c))/c);return this},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);retur [...]
+-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},setLength:func [...]
+this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b [...]
+a.array[b+1];return this},rotateAround:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=this.x-a.x,g=this.y-a.y;this.x=e*c-g*d+a.x;this.y=e*d+g*c+a.y;return this}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0};
+THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:thr [...]
+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return th [...]
+b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .m [...]
+this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){isFinite(a)?(this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a;return function(b){!1===b instanceof THREE.Euler&&console.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion) [...]
+return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+ [...]
+return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,g=a.y,f=a.z;a=a.w;var h=a*b+g*d-f*c,l=a*c+f*b-e*d,k=a*d+e*c-g*b,b=-e*b-g*c-f*d;this.x=h*a+b*-e+l*-f-k*-g;this.y=l*a+b*-g+k*-e-h*-f;this.z=k*a+b*-f+h*-g-l*-e;return this},projec [...]
+return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(),unproject:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[1 [...]
+return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Mat [...]
+this.z));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3,b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();this.multiplyScalar(Math.max(a,Math.min(b,c))/c);return this},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);retu [...]
+round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+t [...]
+length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.multiplyScalar(a/this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},cross:func [...]
+b)return console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,g=b.x,f=b.y,h=b.z;this.x=d*h-e*f;this.y=e*g-c*h;this.z=c*f-d*g;return this},projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);retu [...]
+projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this [...]
+this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(a,b){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")},getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition [...]
+getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a,b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},setFromMatrixScale:function(a){var b=this.set(a [...]
+a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length();a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:functi [...]
+a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];return this}};THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1};
+THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){ca [...]
+case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;ret [...]
+addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return thi [...]
+a;this.y-=a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){isFinite(a)?(this.x*=a,this.y*=a,this.z*=a,this.w*=a):this.w=this.z=this.y=this.x=0;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;r [...]
+divideScalar:function(a){return this.multiplyScalar(1/a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var g=a[8],f=a[1],h=a[5],l=a[9];c=a[2];b=a[6];var k=a[10];if(.01>Math.abs(d-f)&&.01>Math.abs(g-c)&&.01>Math.abs(l-b)){if(.1>Math.abs(d+f)&&.1>Math.abs(g+c)&&.1>Math.abs(l+b [...]
+h+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;k=(k+1)/2;d=(d+f)/4;g=(g+c)/4;l=(l+b)/4;e>h&&e>k?.01>e?(b=0,d=c=.707106781):(b=Math.sqrt(e),c=d/b,d=g/b):h>k?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h),b=d/c,d=l/c):.01>k?(c=b=.707106781,d=0):(d=Math.sqrt(k),b=g/d,c=l/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-l)*(b-l)+(g-c)*(g-c)+(f-d)*(f-d));.001>Math.abs(a)&&(a=1);this.x=(b-l)/a;this.y=(g-c)/a;this.z=(f-d)/a;this.w=Math.acos((e+h+k-1)/2);return this},mi [...]
+Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(){var a,b;r [...]
+d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(th [...]
+roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},l [...]
+this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.multiplyScalar(a/this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this [...]
+this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];this.w=a.array[b+3];return this}};
+THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ";
+THREE.Euler.prototype={constructor:THREE.Euler,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order},set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},clone:function(){return new this.construc [...]
+this._y,this._z,this._order)},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=THREE.Math.clamp,e=a.elements;a=e[0];var g=e[4],f=e[8],h=e[1],l=e[5],k=e[9],m=e[2],p=e[6],e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(-k,e),this._z=Math.atan2(-g,a)):(this._x=Math.atan2(p,l),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(k,-1,1)), [...]
+(this._y=Math.atan2(f,e),this._z=Math.atan2(h,l)):(this._y=Math.atan2(-m,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(p,-1,1)),.99999>Math.abs(p)?(this._y=Math.atan2(-m,e),this._z=Math.atan2(-g,l)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(m,-1,1)),.99999>Math.abs(m)?(this._x=Math.atan2(p,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-g,l))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-k,l),this._y=Math.atan2(-m,a [...]
+0,this._y=Math.atan2(f,e))):"XZY"===b?(this._z=Math.asin(-d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(p,l),this._y=Math.atan2(f,a)):(this._x=Math.atan2(-k,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeRotationFromQuaternion(b);this.setFromRotationMatrix(a,c,d);return this}}() [...]
+b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=th [...]
+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new THREE.Vector3(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3};
+THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.e [...]
+at:function(a,b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start) [...]
+this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)};
+THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.min.copy(a.min [...]
+return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y},center:function(a){return(a||new THREE.Vector2).addVectors(this.min,this.max).multiplyScalar(.5)},size:function(a){return(a||new THREE.Vector2).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return  [...]
+this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector2).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this [...]
+this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(th [...]
+a.max.equals(this.max)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)};
+THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new THREE.Vector3;return function(b,c){var d=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),setFromObject:function(){var a=new THREE.Vector3;return function(b){var c=this;b.updateMatrixW [...]
+this.makeEmpty();b.traverse(function(b){var e=b.geometry;if(void 0!==e)if(e instanceof THREE.Geometry)for(var g=e.vertices,e=0,f=g.length;e<f;e++)a.copy(g[e]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a);else if(e instanceof THREE.BufferGeometry&&void 0!==e.attributes.position)for(g=e.attributes.position.array,e=0,f=g.length;e<f;e+=3)a.set(g[e],g[e+1],g[e+2]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a)});return this}}(),clone:function(){return(new this.constructor).copy(this)},c [...]
+this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z},center:function(a){return(a||new THREE.Vector3).addVectors(this.min,this.max).multiplyScalar(.5)},size:function(a){return(a||new THREE.Vector3).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this}, [...]
+this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y||a.z<this.min.z||a.z>this.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector3).set((a.x-this.min.x)/(th [...]
+this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y||a.max.z<this.min.z||a.min.z>this.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSp [...]
+new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,th [...]
+this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this} [...]
+this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}};THREE.Matrix3=function(){this.elements=new Float32Array([1,0,0,0,1,0,0,0,1]);0<arguments.length&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")};
+THREE.Matrix3.prototype={constructor:THREE.Matrix3,set:function(a,b,c,d,e,g,f,h,l){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=g;k[2]=f;k[5]=h;k[8]=l;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("THREE.Matrix3: .multiplyVector3() has be [...]
+return a.applyMatrix3(this)},multiplyVector3Array:function(a){console.warn("THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.");return this.applyToVector3Array(a)},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.fromArray(b,c),a.applyMatrix3(this),a.toArray(b,c);return b}}(),applyToBuffer:function(){var a;return funct [...]
+a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length/b.itemSize);for(var e=0;e<d;e++,c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix3(this),b.setXYZ(a.x,a.y,a.z);return b}}(),multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*=a;b[6]*=a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],g=a[4],f=a[5],h=a[6],l=a[7],a=a[8];return b*g*a-b*f*l-c*e*a+c*f*h+d*e*l-d*g*h},getInvers [...]
+b){var c=a.elements,d=this.elements;d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4];c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return th [...]
+c);return this},transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5] [...]
+b[2];a[7]=b[5];a[8]=b[8];return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]}};THREE.Matrix4=function(){this.elements=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);0<arguments.length&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")};
+THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,g,f,h,l,k,m,p,n,q,s,t){var v=this.elements;v[0]=a;v[4]=b;v[8]=c;v[12]=d;v[1]=e;v[5]=g;v[9]=f;v[13]=h;v[2]=l;v[6]=k;v[10]=m;v[14]=p;v[3]=n;v[7]=q;v[11]=s;v[15]=t;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new THREE.Matrix4).fromArray(this.elements)},copy:function(a){this.elements.set(a.elements);return this},extractPosition:function(a){console.warn [...]
+return this.copyPosition(a)},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){var d=this.elements;a.set(d[0],d[1],d[2]);b.set(d[4],d[5],d[6]);c.set(d[8],d[9],d[10]);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);var c=this.elements;b=b.elements;var d=1/a [...]
+b[1],b[2]).length(),e=1/a.set(b[4],b[5],b[6]).length(),g=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*g;c[9]=b[9]*g;c[10]=b[10]*g;return this}}(),makeRotationFromEuler:function(a){!1===a instanceof THREE.Euler&&console.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,g=Math.cos(c),c=Math.sin(c),f=Math.cos(d),d=Math.sin(d [...]
+e=Math.sin(e);if("XYZ"===a.order){a=g*h;var l=g*e,k=c*h,m=c*e;b[0]=f*h;b[4]=-f*e;b[8]=d;b[1]=l+k*d;b[5]=a-m*d;b[9]=-c*f;b[2]=m-a*d;b[6]=k+l*d;b[10]=g*f}else"YXZ"===a.order?(a=f*h,l=f*e,k=d*h,m=d*e,b[0]=a+m*c,b[4]=k*c-l,b[8]=g*d,b[1]=g*e,b[5]=g*h,b[9]=-c,b[2]=l*c-k,b[6]=m+a*c,b[10]=g*f):"ZXY"===a.order?(a=f*h,l=f*e,k=d*h,m=d*e,b[0]=a-m*c,b[4]=-g*e,b[8]=k+l*c,b[1]=l+k*c,b[5]=g*h,b[9]=m-a*c,b[2]=-g*d,b[6]=c,b[10]=g*f):"ZYX"===a.order?(a=g*h,l=g*e,k=c*h,m=c*e,b[0]=f*h,b[4]=k*d-l,b[8]=a*d+m,b [...]
+m*d+a,b[9]=l*d-k,b[2]=-d,b[6]=c*f,b[10]=g*f):"YZX"===a.order?(a=g*f,l=g*d,k=c*f,m=c*d,b[0]=f*h,b[4]=m-a*e,b[8]=k*e+l,b[1]=e,b[5]=g*h,b[9]=-c*h,b[2]=-d*h,b[6]=l*e+k,b[10]=a-m*e):"XZY"===a.order&&(a=g*f,l=g*d,k=c*f,m=c*d,b[0]=f*h,b[4]=-e,b[8]=d*h,b[1]=a*e+m,b[5]=g*h,b[9]=l*e-k,b[2]=k*e-l,b[6]=c*h,b[10]=m*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to  [...]
+return this.makeRotationFromQuaternion(a)},makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,g=a.w,f=c+c,h=d+d,l=e+e;a=c*f;var k=c*h,c=c*l,m=d*h,d=d*l,e=e*l,f=g*f,h=g*h,g=g*l;b[0]=1-(m+e);b[4]=k-g;b[8]=c+h;b[1]=k+g;b[5]=1-(a+e);b[9]=d-f;b[2]=c-h;b[6]=d+f;b[10]=1-(a+m);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a,b,c;return function(d,e,g){void 0===a&&(a=new THREE.Vector3);void 0===b&&(b=new THREE.Vector3);void 0===c [...]
+var f=this.elements;c.subVectors(d,e).normalize();0===c.lengthSq()&&(c.z=1);a.crossVectors(g,c).normalize();0===a.lengthSq()&&(c.x+=1E-4,a.crossVectors(g,c).normalize());b.crossVectors(c,a);f[0]=a.x;f[4]=b.x;f[8]=c.x;f[1]=a.y;f[5]=b.y;f[9]=c.y;f[2]=a.z;f[6]=b.z;f[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices [...]
+multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,g=c[0],f=c[4],h=c[8],l=c[12],k=c[1],m=c[5],p=c[9],n=c[13],q=c[2],s=c[6],t=c[10],v=c[14],u=c[3],w=c[7],D=c[11],c=c[15],x=d[0],B=d[4],y=d[8],z=d[12],A=d[1],J=d[5],F=d[9],C=d[13],N=d[2],L=d[6],Q=d[10],M=d[14],K=d[3],E=d[7],O=d[11],d=d[15];e[0]=g*x+f*A+h*N+l*K;e[4]=g*B+f*J+h*L+l*E;e[8]=g*y+f*F+h*Q+l*O;e[12]=g*z+f*C+h*M+l*d;e[1]=k*x+m*A+p*N+n*K;e[5]=k*B+m*J+p*L+n*E;e[9]=k*y+m*F+p*Q+n*O;e[13]=k*z+m*C+p*M+n*d;e[2]=q*x+ [...]
+K;e[6]=q*B+s*J+t*L+v*E;e[10]=q*y+s*F+t*Q+v*O;e[14]=q*z+s*C+t*M+v*d;e[3]=u*x+w*A+D*N+c*K;e[7]=u*B+w*J+D*L+c*E;e[11]=u*y+w*F+D*Q+c*O;e[15]=u*z+w*C+D*M+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a [...]
+b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},multiplyVector3:function(a){console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.");return a.applyProjection(this)},multiplyVector4:function(a){console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(t [...]
+return this.applyToVector3Array(a)},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.fromArray(b,c),a.applyMatrix4(this),a.toArray(b,c);return b}}(),applyToBuffer:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length/b.itemSize);for(var e=0;e<d;e++,c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix4(this [...]
+a.y,a.z);return b}}(),rotateAxis:function(a){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.");a.transformDirection(this)},crossVector:function(a){console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],g=a[1],f=a[5],h=a[9],l=a[13],k=a[2],m=a[6],p=a[10],n=a[14];return a[3]*(+e [...]
+m-e*f*p+c*l*p+d*f*n-c*h*n)+a[7]*(+b*h*n-b*l*p+e*g*p-d*g*n+d*l*k-e*h*k)+a[11]*(+b*l*m-b*f*n-e*g*m+c*g*n+e*f*k-c*l*k)+a[15]*(-d*f*k-b*h*m+b*f*p+d*g*m-c*g*p+c*h*k)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[ [...]
+c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a;return function(){void 0===a&&(a=new THREE.Vector3);console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:funct [...]
+this.elements,d=a.elements,e=d[0],g=d[4],f=d[8],h=d[12],l=d[1],k=d[5],m=d[9],p=d[13],n=d[2],q=d[6],s=d[10],t=d[14],v=d[3],u=d[7],w=d[11],d=d[15];c[0]=m*t*u-p*s*u+p*q*w-k*t*w-m*q*d+k*s*d;c[4]=h*s*u-f*t*u-h*q*w+g*t*w+f*q*d-g*s*d;c[8]=f*p*u-h*m*u+h*k*w-g*p*w-f*k*d+g*m*d;c[12]=h*m*q-f*p*q-h*k*s+g*p*s+f*k*t-g*m*t;c[1]=p*s*v-m*t*v-p*n*w+l*t*w+m*n*d-l*s*d;c[5]=f*t*v-h*s*v+h*n*w-e*t*w-f*n*d+e*s*d;c[9]=h*m*v-f*p*v-h*l*w+e*p*w+f*l*d-e*m*d;c[13]=f*p*n-h*m*n+h*l*s-e*p*s-f*l*t+e*m*t;c[2]=k*t*v-p*q*v+ [...]
+u-k*n*d+l*q*d;c[6]=h*q*v-g*t*v-h*n*u+e*t*u+g*n*d-e*q*d;c[10]=g*p*v-h*k*v+h*l*u-e*p*u-g*l*d+e*k*d;c[14]=h*k*n-g*p*n-h*l*q+e*p*q+g*l*t-e*k*t;c[3]=m*q*v-k*s*v-m*n*u+l*s*u+k*n*w-l*q*w;c[7]=g*s*v-f*q*v+f*n*u-e*s*u-g*n*w+e*q*w;c[11]=f*k*v-g*m*v-f*l*u+e*m*u+g*l*w-e*k*w;c[15]=g*m*n-f*k*n+f*l*q-e*m*q-g*l*s+e*k*s;c=e*c[0]+l*c[4]+n*c[8]+v*c[12];if(0===c){if(b)throw Error("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");console.warn("THREE.Matrix4.getInverse(): can't invert matri [...]
+this.identity();return this}this.multiplyScalar(1/c);return this},translate:function(a){console.error("THREE.Matrix4: .translate() has been removed.")},rotateX:function(a){console.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(a){console.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(a){console.error("THREE.Matrix4: .rotateZ() has been removed.")},rotateByAxis:function(a,b){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")}, [...]
+this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10]))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0, [...]
+return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,g=a.x,f=a.y,h=a.z,l=e*g,k=e*f;this.set(l*g+c,l*f-d*h,l*h+d*f,0,l*f+d*h,k*f+c,k*h-d*g,0,l*h-d*f,k*h+d*g,e*h*h+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b, [...]
+0,0,0,0,1);return this},compose:function(a,b,c){this.makeRotationFromQuaternion(b);this.scale(c);this.setPosition(a);return this},decompose:function(){var a,b;return function(c,d,e){void 0===a&&(a=new THREE.Vector3);void 0===b&&(b=new THREE.Matrix4);var g=this.elements,f=a.set(g[0],g[1],g[2]).length(),h=a.set(g[4],g[5],g[6]).length(),l=a.set(g[8],g[9],g[10]).length();0>this.determinant()&&(f=-f);c.x=g[12];c.y=g[13];c.z=g[14];b.elements.set(this.elements);c=1/f;var g=1/h,k=1/l;b.elements[ [...]
+c;b.elements[2]*=c;b.elements[4]*=g;b.elements[5]*=g;b.elements[6]*=g;b.elements[8]*=k;b.elements[9]*=k;b.elements[10]*=k;d.setFromRotationMatrix(b);e.x=f;e.y=h;e.z=l;return this}}(),makeFrustum:function(a,b,c,d,e,g){var f=this.elements;f[0]=2*e/(b-a);f[4]=0;f[8]=(b+a)/(b-a);f[12]=0;f[1]=0;f[5]=2*e/(d-c);f[9]=(d+c)/(d-c);f[13]=0;f[2]=0;f[6]=0;f[10]=-(g+e)/(g-e);f[14]=-2*g*e/(g-e);f[3]=0;f[7]=0;f[11]=-1;f[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRa [...]
+var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,g){var f=this.elements,h=b-a,l=c-d,k=g-e;f[0]=2/h;f[4]=0;f[8]=0;f[12]=-((b+a)/h);f[1]=0;f[5]=2/l;f[9]=0;f[13]=-((c+d)/l);f[2]=0;f[6]=0;f[10]=-2/k;f[14]=-((g+e)/k);f[3]=0;f[7]=0;f[11]=0;f[15]=1;return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elemen [...]
+a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]}};THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3};
+THREE.Ray.prototype={constructor:THREE.Ray,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPo [...]
+b){var c=b||new THREE.Vector3;c.subVectors(a,this.origin);var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.dis [...]
+distanceSqToSegment:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,g,f){a.copy(d).add(e).multiplyScalar(.5);b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a);var h=.5*d.distanceTo(e),l=-this.direction.dot(b),k=c.dot(this.direction),m=-c.dot(b),p=c.lengthSq(),n=Math.abs(1-l*l),q;0<n?(d=l*m-k,e=l*k-m,q=h*n,0<=d?e>=-q?e<=q?(h=1/n,d*=h,e*=h,l=d*(d+l*e+2*k)+e*(l*d+e+2*m)+p):(e=h,d=Math.max(0,-(l*e+k)),l=-d*d+e*(e+2*m)+p):(e=-h,d=Math.max(0 [...]
+l=-d*d+e*(e+2*m)+p):e<=-q?(d=Math.max(0,-(-l*h+k)),e=0<d?-h:Math.min(Math.max(-h,-m),h),l=-d*d+e*(e+2*m)+p):e<=q?(d=0,e=Math.min(Math.max(-h,-m),h),l=e*(e+2*m)+p):(d=Math.max(0,-(l*h+k)),e=0<d?h:Math.min(Math.max(-h,-m),h),l=-d*d+e*(e+2*m)+p)):(e=0<l?-h:h,d=Math.max(0,-(l*e+k)),l=-d*d+e*(e+2*m)+p);g&&g.copy(this.direction).multiplyScalar(d).add(this.origin);f&&f.copy(b).multiplyScalar(e).add(a);return l}}(),isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius} [...]
+new THREE.Vector3;return function(b,c){a.subVectors(b.center,this.origin);var d=a.dot(this.direction),e=a.dot(a)-d*d,g=b.radius*b.radius;if(e>g)return null;g=Math.sqrt(g-e);e=d-g;d+=g;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)?0:null;a=-(this. [...]
+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new THREE.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,g,f;d=1/this.direction.x;g=1/this.direction.y;f=1/this.direction.z;var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=g?(e=(a.min.y-h.y)*g,g*=a.max.y-h.y):(e=(a.max.y-h. [...]
+h.y);if(c>g||e>d)return null;if(e>c||c!==c)c=e;if(g<d||d!==d)d=g;0<=f?(e=(a.min.z-h.z)*f,f*=a.max.z-h.z):(e=(a.max.z-h.z)*f,f*=a.min.z-h.z);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(f<d||d!==d)d=f;return 0>d?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,g,f,h,l){b.subVectors(g,e);c.subVectors(f,e);d.crossVectors(b,c);g=this.direction.dot(d);if(0<g){if(h)return null;h=1}else i [...]
+g=-g;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;f=h*this.direction.dot(b.cross(a));if(0>f||e+f>g)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/g,l)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}};
+THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0};
+THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,g=0,f=b.length;g<f;g++)e=Math.max(e,d.distanceToSquared(b[g]));this.radius=Math.sqrt(e);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.center.copy(a.center);this.radius=a.radius;retu [...]
+empty:function(){return 0>=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this [...]
+return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius}};
+THREE.Frustum=function(a,b,c,d,e,g){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==g?g:new THREE.Plane]};
+THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,g){var f=this.planes;f[0].copy(a);f[1].copy(b);f[2].copy(c);f[3].copy(d);f[4].copy(e);f[5].copy(g);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],g=c[3],f=c[4],h=c[5],l=c[6],k=c[7],m=c[8],p=c[9],n=c[10],q=c[11],s=c[12],t=c[13 [...]
+c=c[15];b[0].setComponents(g-a,k-f,q-m,c-s).normalize();b[1].setComponents(g+a,k+f,q+m,c+s).normalize();b[2].setComponents(g+d,k+h,q+p,c+t).normalize();b[3].setComponents(g-d,k-h,q-p,c-t).normalize();b[4].setComponents(g-e,k-l,q-n,c-v).normalize();b[5].setComponents(g+e,k+l,q+n,c+v).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.mat [...]
+return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes,c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var g=d[e];a.x=0<g.normal.x?c.min.x:c.max.x;b.x=0<g.normal.x?c.max.x:c.min.x;a.y=0<g.normal.y?c.min.y:c.max.y;b.y=0<g.normal.y?c.max.y:c.min.y;a.z=0<g.normal.z?c.min.z:c.max.z;b.z=0<g.normal.z?c. [...]
+var f=g.distanceToPoint(a),g=g.distanceToPoint(b);if(0>f&&0>g)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0};
+THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCopla [...]
+c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},project [...]
+b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a,b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start);a=this.distanceToPoint(a.end);return 0>b&&0<a||0>a&&0<b},intersectLine:function(){var a=new THREE.Vector3;return function(b,c){var d=c||new THREE.Vector3,e=b.delta(a),g=this.normal.dot(e);if(0===g){if(0===this.distanceToPoint(b.start))return d.copy(b.start [...]
+-(b.start.dot(this.normal)+this.constant)/g,0>g||1<g?void 0:d.copy(e).multiplyScalar(g).add(b.start)}}(),coplanarPoint:function(a){return(a||new THREE.Vector3).copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Matrix3;return function(d,e){var g=e||c.getNormalMatrix(d),g=a.copy(this.normal).applyMatrix3(g),f=this.coplanarPoint(b);f.applyMatrix4(d);this.setFromNormalAndCoplanarPoint(g,f);return this}}(),transla [...]
+a.dot(this.normal);return this},equals:function(a){return a.normal.equals(this.normal)&&a.constant===this.constant}};
+THREE.Math={generateUUID:function(){var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),b=Array(36),c=0,d;return function(){for(var e=0;36>e;e++)8===e||13===e||18===e||23===e?b[e]="-":14===e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19===e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b) [...]
+b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(){var a=Math.PI/180;return function(b){retur [...]
+radToDeg:function(){var a=180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},nearestPowerOfTwo:function(a){return Math.pow(2,Math.round(Math.log(a)/Math.LN2))},nextPowerOfTwo:function(a){a--;a|=a>>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}};
+THREE.Spline=function(a){function b(a,b,c,d,e,g,f){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*f+(-3*(b-c)-2*a-d)*g+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,g,f,h,l,k,m,p,n;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;g=Math.floor(e);f=e-g;c[0]=0===g?g:g-1;c[1]=g;c[2]=g>this.points.length-2?this.points.length-1:g+1;c[3]=g>this.points.length-3?this.points.le [...]
+2;k=this.points[c[0]];m=this.points[c[1]];p=this.points[c[2]];n=this.points[c[3]];h=f*f;l=f*h;d.x=b(k.x,m.x,p.x,n.x,f,h,l);d.y=b(k.y,m.y,p.y,n.y,f,h,l);d.z=b(k.z,m.z,p.z,n.z,f,h,l);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,g=new THREE.Vector3,f=new THREE.Vector3,h=[],l=0;h[0]=0;a||(a=100);c=this.points.length*a;g.copy(this.points[0]);for(a=1;a [...]
+a/c,d=this.getPoint(b),f.copy(d),l+=f.distanceTo(g),g.copy(d),b*=this.points.length-1,b=Math.floor(b),b!==e&&(h[b]=l,e=b);h[h.length]=l;return{chunks:h,total:l}};this.reparametrizeByArcLength=function(a){var b,c,d,e,g,f,h=[],l=new THREE.Vector3,k=this.getLength();h.push(l.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=k.chunks[b]-k.chunks[b-1];f=Math.ceil(a*c/k.total);e=(b-1)/(this.points.length-1);g=b/(this.points.length-1);for(c=1;c<f-1;c++)d=e+1/f*c*(g-e),d=this.get [...]
+h.push(l.copy(d).clone());h.push(l.copy(this.points[b]).clone())}this.points=h}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}();
+THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,g,f,h){a.subVectors(f,e);b.subVectors(g,e);c.subVectors(d,e);d=a.dot(a);e=a.dot(b);g=a.dot(c);var l=b.dot(b);f=b.dot(c);var k=d*l-e*e;h=h||new THREE.Vector3;if(0===k)return h.set(-2,-1,-1);k=1/k;l=(l*g-e*f)*k;d=(d*f-e*g)*k;return h.set(1-l-d,d,l)}}();
+THREE.Triangle.containsPoint=function(){var a=new THREE.Vector3;return function(b,c,d,e){b=THREE.Triangle.barycoordFromPoint(b,c,d,e,a);return 0<=b.x&&0<=b.y&&1>=b.x+b.y}}();
+THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVe [...]
+this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a||new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b, [...]
+equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}};THREE.Channels=function(){this.mask=1};THREE.Channels.prototype={constructor:THREE.Channels,set:function(a){this.mask=1<<a},enable:function(a){this.mask|=1<<a},toggle:function(a){this.mask^=1<<a},disable:function(a){this.mask&=~(1<<a)}};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1};
+THREE.Clock.prototype={constructor:THREE.Clock,start:function(){this.oldTime=this.startTime=self.performance.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=self.performance.now(),a=.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){};
+THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a] [...]
+c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners[a];if(void 0!==c){var d=c.indexOf(b);-1!==d&&c.splice(d,1)}}},dispatchEvent:function(a){if(void 0!==this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;for(var c=[],d=b.length,e=0;e<d;e++)c[e]=b[e];for(e=0;e<d;e++)c[e].call(this,a)}}}};
+(function(a){function b(a,b){return a.distance-b.distance}function c(a,b,g,f){if(!1!==a.visible&&(a.raycast(b,g),!0===f)){a=a.children;f=0;for(var h=a.length;f<h;f++)c(a[f],b,g,!0)}}a.Raycaster=function(b,c,g,f){this.ray=new a.Ray(b,c);this.near=g||0;this.far=f||Infinity;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");re [...]
+a.Raycaster.prototype={constructor:a.Raycaster,linePrecision:1,set:function(a,b){this.ray.set(a,b)},setFromCamera:function(b,c){c instanceof a.PerspectiveCamera?(this.ray.origin.setFromMatrixPosition(c.matrixWorld),this.ray.direction.set(b.x,b.y,.5).unproject(c).sub(this.ray.origin).normalize()):c instanceof a.OrthographicCamera?(this.ray.origin.set(b.x,b.y,-1).unproject(c),this.ray.direction.set(0,0,-1).transformDirection(c.matrixWorld)):console.error("THREE.Raycaster: Unsupported camer [...]
+intersectObject:function(a,e){var g=[];c(a,this,g,e);g.sort(b);return g},intersectObjects:function(a,e){var g=[];if(!1===Array.isArray(a))return console.warn("THREE.Raycaster.intersectObjects: objects is not an Array."),g;for(var f=0,h=a.length;f<h;f++)c(a[f],this,g,e);g.sort(b);return g}}})(THREE);
+THREE.Object3D=function(){Object.defineProperty(this,"id",{value:THREE.Object3DIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Object3D";this.parent=null;this.channels=new THREE.Channels;this.children=[];this.up=THREE.Object3D.DefaultUp.clone();var a=new THREE.Vector3,b=new THREE.Euler,c=new THREE.Quaternion,d=new THREE.Vector3(1,1,1);b.onChange(function(){c.setFromEuler(b,!1)});c.onChange(function(){b.setFromQuaternion(c,void 0,!1)});Object.defineProperties(this, [...]
+value:a},rotation:{enumerable:!0,value:b},quaternion:{enumerable:!0,value:c},scale:{enumerable:!0,value:d},modelViewMatrix:{value:new THREE.Matrix4},normalMatrix:{value:new THREE.Matrix3}});this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixAutoUpdate=THREE.Object3D.DefaultMatrixAutoUpdate;this.matrixWorldNeedsUpdate=!1;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this.renderOrder=0;this.userData={}};
+THREE.Object3D.DefaultUp=new THREE.Vector3(0,1,0);THREE.Object3D.DefaultMatrixAutoUpdate=!0;
+THREE.Object3D.prototype={constructor:THREE.Object3D,get eulerOrder(){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");return this.rotation.order},set eulerOrder(a){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");this.rotation.order=a},get useQuaternion(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")},set useQuaternion(a){console.warn("THREE.Object3D: .useQuaternion has been removed. Th [...]
+applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix);this.matrix.decompose(this.position,this.quaternion,this.scale)},setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a,!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)},setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new THREE.Quaternion;return function(b,c){a [...]
+c);this.quaternion.multiply(a);return this}}(),rotateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a=new THREE.Vector3(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.rotateOnAxis(a,b)}}(),translateOnAxis:function(){var a=new THREE.Vector3;return function(b,c){a.copy(b).applyQuaternion(this.quaternion);this.position.add(a.m [...]
+return this}}(),translate:function(a,b){console.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.");return this.translateOnAxis(b,a)},translateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a=new THREE.Vector3(0,1,0);return function(b){return this.translateOnAxis(a,b)}}(),translateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.trans [...]
+b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new THREE.Matrix4;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new THREE.Matrix4;return function(b){a.lookAt(b,this.position,this.up);this.quaternion.setFromRotationMatrix(a)}}(),add:function(a){if(1<arguments.length){for(var b=0;b<arguments.length;b++)this.add(arguments[b]);return this}if(a===this)return console.error("THREE.Objec [...]
+a),this;a instanceof THREE.Object3D?(null!==a.parent&&a.parent.remove(a),a.parent=this,a.dispatchEvent({type:"added"}),this.children.push(a)):console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.",a);return this},remove:function(a){if(1<arguments.length)for(var b=0;b<arguments.length;b++)this.remove(arguments[b]);b=this.children.indexOf(a);-1!==b&&(a.parent=null,a.dispatchEvent({type:"removed"}),this.children.splice(b,1))},getChildByName:function(a){console.warn("T [...]
+return this.getObjectByName(a)},getObjectById:function(a){return this.getObjectByProperty("id",a)},getObjectByName:function(a){return this.getObjectByProperty("name",a)},getObjectByProperty:function(a,b){if(this[a]===b)return this;for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c].getObjectByProperty(a,b);if(void 0!==e)return e}},getWorldPosition:function(a){a=a||new THREE.Vector3;this.updateMatrixWorld(!0);return a.setFromMatrixPosition(this.matrixWorld)},getWorldQuatern [...]
+new THREE.Vector3,b=new THREE.Vector3;return function(c){c=c||new THREE.Quaternion;this.updateMatrixWorld(!0);this.matrixWorld.decompose(a,c,b);return c}}(),getWorldRotation:function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Euler;this.getWorldQuaternion(a);return b.setFromQuaternion(a,this.rotation.order,!1)}}(),getWorldScale:function(){var a=new THREE.Vector3,b=new THREE.Quaternion;return function(c){c=c||new THREE.Vector3;this.updateMatrixWorld(!0);this.matrixWorl [...]
+b,c);return c}}(),getWorldDirection:function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,1).applyQuaternion(a)}}(),raycast:function(){},traverse:function(a){a(this);for(var b=this.children,c=0,d=b.length;c<d;c++)b[c].traverse(a)},traverseVisible:function(a){if(!1!==this.visible){a(this);for(var b=this.children,c=0,d=b.length;c<d;c++)b[c].traverseVisible(a)}},traverseAncestors:function(a){var b=this.parent;null!==b&&(a [...]
+updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale);this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){!0===this.matrixAutoUpdate&&this.updateMatrix();if(!0===this.matrixWorldNeedsUpdate||!0===a)null===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},toJSON:fu [...]
+[],c;for(c in a){var d=a[c];delete d.metadata;b.push(d)}return b}var c=void 0===a,d={};c&&(a={geometries:{},materials:{},textures:{},images:{}},d.metadata={version:4.4,type:"Object",generator:"Object3D.toJSON"});var e={};e.uuid=this.uuid;e.type=this.type;""!==this.name&&(e.name=this.name);"{}"!==JSON.stringify(this.userData)&&(e.userData=this.userData);!0===this.castShadow&&(e.castShadow=!0);!0===this.receiveShadow&&(e.receiveShadow=!0);!1===this.visible&&(e.visible=!1);e.matrix=this.mat [...]
+void 0!==this.geometry&&(void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON(a)),e.geometry=this.geometry.uuid);void 0!==this.material&&(void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON(a)),e.material=this.material.uuid);if(0<this.children.length){e.children=[];for(var g=0;g<this.children.length;g++)e.children.push(this.children[g].toJSON(a).object)}if(c){var c=b(a.geometries),g=b(a.materials),f= [...]
+a=b(a.images);0<c.length&&(d.geometries=c);0<g.length&&(d.materials=g);0<f.length&&(d.textures=f);0<a.length&&(d.images=a)}d.object=e;return d},clone:function(a){return(new this.constructor).copy(this,a)},copy:function(a,b){void 0===b&&(b=!0);this.name=a.name;this.up.copy(a.up);this.position.copy(a.position);this.quaternion.copy(a.quaternion);this.scale.copy(a.scale);this.rotationAutoUpdate=a.rotationAutoUpdate;this.matrix.copy(a.matrix);this.matrixWorld.copy(a.matrixWorld);this.matrixAu [...]
+a.matrixAutoUpdate;this.matrixWorldNeedsUpdate=a.matrixWorldNeedsUpdate;this.visible=a.visible;this.castShadow=a.castShadow;this.receiveShadow=a.receiveShadow;this.frustumCulled=a.frustumCulled;this.renderOrder=a.renderOrder;this.userData=JSON.parse(JSON.stringify(a.userData));if(!0===b)for(var c=0;c<a.children.length;c++)this.add(a.children[c].clone());return this}};THREE.EventDispatcher.prototype.apply(THREE.Object3D.prototype);THREE.Object3DIdCount=0;
+THREE.Face3=function(a,b,c,d,e,g){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=Array.isArray(d)?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=Array.isArray(e)?e:[];this.materialIndex=void 0!==g?g:0};
+THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a=a.a;this.b=a.b;this.c=a.c;this.normal.copy(a.normal);this.color.copy(a.color);this.materialIndex=a.materialIndex;for(var b=0,c=a.vertexNormals.length;b<c;b++)this.vertexNormals[b]=a.vertexNormals[b].clone();b=0;for(c=a.vertexColors.length;b<c;b++)this.vertexColors[b]=a.vertexColors[b].clone();return this}};
+THREE.Face4=function(a,b,c,d,e,g,f){console.warn("THREE.Face4 has been removed. A THREE.Face3 will be created instead.");return new THREE.Face3(a,b,c,e,g,f)};THREE.BufferAttribute=function(a,b){this.uuid=THREE.Math.generateUUID();this.array=a;this.itemSize=b;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.version=0};
+THREE.BufferAttribute.prototype={constructor:THREE.BufferAttribute,get length(){console.warn("THREE.BufferAttribute: .length has been deprecated. Please use .count.");return this.array.length},get count(){return this.array.length/this.itemSize},set needsUpdate(a){!0===a&&this.version++},setDynamic:function(a){this.dynamic=a;return this},copy:function(a){this.array=new a.array.constructor(a.array);this.itemSize=a.itemSize;this.dynamic=a.dynamic;return this},copyAt:function(a,b,c){a*=this. [...]
+c*=b.itemSize;for(var d=0,e=this.itemSize;d<e;d++)this.array[a+d]=b.array[c+d];return this},copyArray:function(a){this.array.set(a);return this},copyColorsArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var g=a[d];void 0===g&&(console.warn("THREE.BufferAttribute.copyColorsArray(): color is undefined",d),g=new THREE.Color);b[c++]=g.r;b[c++]=g.g;b[c++]=g.b}return this},copyIndicesArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var g=a[d];b[c++]=g.a;b[c [...]
+g.c}return this},copyVector2sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var g=a[d];void 0===g&&(console.warn("THREE.BufferAttribute.copyVector2sArray(): vector is undefined",d),g=new THREE.Vector2);b[c++]=g.x;b[c++]=g.y}return this},copyVector3sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var g=a[d];void 0===g&&(console.warn("THREE.BufferAttribute.copyVector3sArray(): vector is undefined",d),g=new THREE.Vector3);b[c++]=g.x;b[c++]=g.y;b[c++]=g [...]
+copyVector4sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var g=a[d];void 0===g&&(console.warn("THREE.BufferAttribute.copyVector4sArray(): vector is undefined",d),g=new THREE.Vector4);b[c++]=g.x;b[c++]=g.y;b[c++]=g.z;b[c++]=g.w}return this},set:function(a,b){void 0===b&&(b=0);this.array.set(a,b);return this},getX:function(a){return this.array[a*this.itemSize]},setX:function(a,b){this.array[a*this.itemSize]=b;return this},getY:function(a){return this.array[a*this.item [...]
+setY:function(a,b){this.array[a*this.itemSize+1]=b;return this},getZ:function(a){return this.array[a*this.itemSize+2]},setZ:function(a,b){this.array[a*this.itemSize+2]=b;return this},getW:function(a){return this.array[a*this.itemSize+3]},setW:function(a,b){this.array[a*this.itemSize+3]=b;return this},setXY:function(a,b,c){a*=this.itemSize;this.array[a+0]=b;this.array[a+1]=c;return this},setXYZ:function(a,b,c,d){a*=this.itemSize;this.array[a+0]=b;this.array[a+1]=c;this.array[a+2]=d;return [...]
+b,c,d,e){a*=this.itemSize;this.array[a+0]=b;this.array[a+1]=c;this.array[a+2]=d;this.array[a+3]=e;return this},clone:function(){return(new this.constructor).copy(this)}};THREE.Int8Attribute=function(a,b){return new THREE.BufferAttribute(new Int8Array(a),b)};THREE.Uint8Attribute=function(a,b){return new THREE.BufferAttribute(new Uint8Array(a),b)};THREE.Uint8ClampedAttribute=function(a,b){return new THREE.BufferAttribute(new Uint8ClampedArray(a),b)};
+THREE.Int16Attribute=function(a,b){return new THREE.BufferAttribute(new Int16Array(a),b)};THREE.Uint16Attribute=function(a,b){return new THREE.BufferAttribute(new Uint16Array(a),b)};THREE.Int32Attribute=function(a,b){return new THREE.BufferAttribute(new Int32Array(a),b)};THREE.Uint32Attribute=function(a,b){return new THREE.BufferAttribute(new Uint32Array(a),b)};THREE.Float32Attribute=function(a,b){return new THREE.BufferAttribute(new Float32Array(a),b)};
+THREE.Float64Attribute=function(a,b){return new THREE.BufferAttribute(new Float64Array(a),b)};THREE.DynamicBufferAttribute=function(a,b){console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.");return(new THREE.BufferAttribute(a,b)).setDynamic(!0)};THREE.InstancedBufferAttribute=function(a,b,c){THREE.BufferAttribute.call(this,a,b);this.meshPerAttribute=c||1};THREE.InstancedBufferAttribute.prototype=Object.create(THREE.Buff [...]
+THREE.InstancedBufferAttribute.prototype.constructor=THREE.InstancedBufferAttribute;THREE.InstancedBufferAttribute.prototype.copy=function(a){THREE.BufferAttribute.prototype.copy.call(this,a);this.meshPerAttribute=a.meshPerAttribute;return this};THREE.InterleavedBuffer=function(a,b){this.uuid=THREE.Math.generateUUID();this.array=a;this.stride=b;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.version=0};
+THREE.InterleavedBuffer.prototype={constructor:THREE.InterleavedBuffer,get length(){return this.array.length},get count(){return this.array.length/this.stride},set needsUpdate(a){!0===a&&this.version++},setDynamic:function(a){this.dynamic=a;return this},copy:function(a){this.array=new a.array.constructor(a.array);this.stride=a.stride;this.dynamic=a.dynamic},copyAt:function(a,b,c){a*=this.stride;c*=b.stride;for(var d=0,e=this.stride;d<e;d++)this.array[a+d]=b.array[c+d];return this},set:fu [...]
+b){void 0===b&&(b=0);this.array.set(a,b);return this},clone:function(){return(new this.constructor).copy(this)}};THREE.InstancedInterleavedBuffer=function(a,b,c){THREE.InterleavedBuffer.call(this,a,b);this.meshPerAttribute=c||1};THREE.InstancedInterleavedBuffer.prototype=Object.create(THREE.InterleavedBuffer.prototype);THREE.InstancedInterleavedBuffer.prototype.constructor=THREE.InstancedInterleavedBuffer;
+THREE.InstancedInterleavedBuffer.prototype.copy=function(a){THREE.InterleavedBuffer.prototype.copy.call(this,a);this.meshPerAttribute=a.meshPerAttribute;return this};THREE.InterleavedBufferAttribute=function(a,b,c){this.uuid=THREE.Math.generateUUID();this.data=a;this.itemSize=b;this.offset=c};
+THREE.InterleavedBufferAttribute.prototype={constructor:THREE.InterleavedBufferAttribute,get length(){console.warn("THREE.BufferAttribute: .length has been deprecated. Please use .count.");return this.array.length},get count(){return this.data.array.length/this.data.stride},setX:function(a,b){this.data.array[a*this.data.stride+this.offset]=b;return this},setY:function(a,b){this.data.array[a*this.data.stride+this.offset+1]=b;return this},setZ:function(a,b){this.data.array[a*this.data.stri [...]
+2]=b;return this},setW:function(a,b){this.data.array[a*this.data.stride+this.offset+3]=b;return this},getX:function(a){return this.data.array[a*this.data.stride+this.offset]},getY:function(a){return this.data.array[a*this.data.stride+this.offset+1]},getZ:function(a){return this.data.array[a*this.data.stride+this.offset+2]},getW:function(a){return this.data.array[a*this.data.stride+this.offset+3]},setXY:function(a,b,c){a=a*this.data.stride+this.offset;this.data.array[a+0]=b;this.data.arra [...]
+return this},setXYZ:function(a,b,c,d){a=a*this.data.stride+this.offset;this.data.array[a+0]=b;this.data.array[a+1]=c;this.data.array[a+2]=d;return this},setXYZW:function(a,b,c,d,e){a=a*this.data.stride+this.offset;this.data.array[a+0]=b;this.data.array[a+1]=c;this.data.array[a+2]=d;this.data.array[a+3]=e;return this}};
+THREE.Geometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Geometry";this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.lineDistancesNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.uvsNeedUpdate= [...]
+this.verticesNeedUpdate=!1};
+THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){a=this.faces[c];a.normal.applyMatrix3(b).normalize();for(var e=0,g=a.vertexNormals.length;e<g;e++)a.vertexNormals[e].applyMatrix3(b).normalize()}null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();this.nor [...]
+this.verticesNeedUpdate=!0},rotateX:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationX(b);this.applyMatrix(a);return this}}(),rotateY:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationY(b);this.applyMatrix(a);return this}}(),rotateZ:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationZ(b);this.applyMatrix(a);return this}}(),translate:function(){var a;return function(b,c,d){void 0===a&&(a= [...]
+a.makeTranslation(b,c,d);this.applyMatrix(a);return this}}(),scale:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeScale(b,c,d);this.applyMatrix(a);return this}}(),lookAt:function(){var a;return function(b){void 0===a&&(a=new THREE.Object3D);a.lookAt(b);a.updateMatrix();this.applyMatrix(a.matrix)}}(),fromBufferGeometry:function(a){function b(a,b,d){var e=void 0!==f?[m[a].clone(),m[b].clone(),m[d].clone()]:[],g=void 0!==h?[c.colors[a].clone(),c.colors[b].cl [...]
+[],e=new THREE.Face3(a,b,d,e,g);c.faces.push(e);void 0!==l&&c.faceVertexUvs[0].push([p[a].clone(),p[b].clone(),p[d].clone()]);void 0!==k&&c.faceVertexUvs[1].push([n[a].clone(),n[b].clone(),n[d].clone()])}var c=this,d=null!==a.index?a.index.array:void 0,e=a.attributes,g=e.position.array,f=void 0!==e.normal?e.normal.array:void 0,h=void 0!==e.color?e.color.array:void 0,l=void 0!==e.uv?e.uv.array:void 0,k=void 0!==e.uv2?e.uv2.array:void 0;void 0!==k&&(this.faceVertexUvs[1]=[]);for(var m=[],p [...]
+q=e=0;e<g.length;e+=3,q+=2)c.vertices.push(new THREE.Vector3(g[e],g[e+1],g[e+2])),void 0!==f&&m.push(new THREE.Vector3(f[e],f[e+1],f[e+2])),void 0!==h&&c.colors.push(new THREE.Color(h[e],h[e+1],h[e+2])),void 0!==l&&p.push(new THREE.Vector2(l[q],l[q+1])),void 0!==k&&n.push(new THREE.Vector2(k[q],k[q+1]));if(void 0!==d)if(g=a.groups,0<g.length)for(e=0;e<g.length;e++)for(var q=g[e],s=q.start,t=q.count,q=s,s=s+t;q<s;q+=3)b(d[q],d[q+1],d[q+2]);else for(e=0;e<d.length;e+=3)b(d[e],d[e+1],d[e+2] [...]
+0;e<g.length/3;e+=3)b(e,e+1,e+2);this.computeFaceNormals();null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.translate(a.x,a.y,a.z);return a},normalize:function(){this.computeBoundingSphere();var a=this.boundingSphere.center,b=this.boundingSphere.radius,b=0===b?1:1/b,c=new THREE.Matrix4;c.set(b,0,0,-b*a [...]
+-b*a.y,0,0,b,-b*a.z,0,0,0,1);this.applyMatrix(c);return this},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],g=this.vertices[e.a],f=this.vertices[e.b];a.subVectors(this.vertices[e.c],f);b.subVectors(g,f);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d;d=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)d[b]=new THREE.Vector3;if(a){var e,g,f,h=new THR [...]
+l=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=this.vertices[c.a],g=this.vertices[c.b],f=this.vertices[c.c],h.subVectors(f,g),l.subVectors(e,g),h.cross(l),d[c.a].add(h),d[c.b].add(h),d[c.c].add(h)}else for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],d[c.a].add(c.normal),d[c.b].add(c.normal),d[c.c].add(c.normal);b=0;for(c=this.vertices.length;b<c;b++)d[b].normalize();a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=c.vertexNormals,3===e.length?(e[0].cop [...]
+e[1].copy(d[c.b]),e[2].copy(d[c.c])):(e[0]=d[c.a].clone(),e[1]=d[c.b].clone(),e[2]=d[c.c].clone())},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++)for(e=this.faces[c],e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone(),e.__originalVertexNormals||(e.__originalVertexNormals=[]),a=0,b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__original [...]
+e.vertexNormals[a].clone();var g=new THREE.Geometry;g.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];e=this.morphNormals[a].faceNormals;var f=this.morphNormals[a].vertexNormals,h,l;c=0;for(d=this.faces.length;c<d;c++)h=new THREE.Vector3,l={a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3},e.push(h),f.push(l)}f=this.morphNormals[a];g.vertices [...]
+g.computeFaceNormals();g.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],h=f.faceNormals[c],l=f.vertexNormals[c],h.copy(e.normal),l.a.copy(e.vertexNormals[0]),l.b.copy(e.vertexNormals[1]),l.c.copy(e.vertexNormals[2])}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){console.warn("THREE.Geometry: .computeTangents() has been removed.")},computeLineDistances:fun [...]
+0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);this.boundingSphere.setFromPoints(this.vertices)},merge:function(a,b,c){if(!1===a instanceof THREE.Geometry)console.error("THREE.Geometry.merge(): geometry  [...]
+a);else{var d,e=this.vertices.length,g=this.vertices,f=a.vertices,h=this.faces,l=a.faces,k=this.faceVertexUvs[0];a=a.faceVertexUvs[0];void 0===c&&(c=0);void 0!==b&&(d=(new THREE.Matrix3).getNormalMatrix(b));for(var m=0,p=f.length;m<p;m++){var n=f[m].clone();void 0!==b&&n.applyMatrix4(b);g.push(n)}m=0;for(p=l.length;m<p;m++){var f=l[m],q,s=f.vertexNormals,t=f.vertexColors,n=new THREE.Face3(f.a+e,f.b+e,f.c+e);n.normal.copy(f.normal);void 0!==d&&n.normal.applyMatrix3(d).normalize();b=0;for( [...]
+g;b++)q=s[b].clone(),void 0!==d&&q.applyMatrix3(d).normalize(),n.vertexNormals.push(q);n.color.copy(f.color);b=0;for(g=t.length;b<g;b++)q=t[b],n.vertexColors.push(q.clone());n.materialIndex=f.materialIndex+c;h.push(n)}m=0;for(p=a.length;m<p;m++)if(c=a[m],d=[],void 0!==c){b=0;for(g=c.length;b<g;b++)d.push(c[b].clone());k.push(d)}}},mergeMesh:function(a){!1===a instanceof THREE.Mesh?console.error("THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.",a):(a.matrixAutoUpdate&&a.up [...]
+this.merge(a.geometry,a.matrix))},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),g,f;g=0;for(f=this.vertices.length;g<f;g++)d=this.vertices[g],d=Math.round(d.x*e)+"_"+Math.round(d.y*e)+"_"+Math.round(d.z*e),void 0===a[d]?(a[d]=g,b.push(this.vertices[g]),c[g]=b.length-1):c[g]=c[a[d]];a=[];g=0;for(f=this.faces.length;g<f;g++)for(e=this.faces[g],e.a=c[e.a],e.b=c[e.b],e.c=c[e.c],e=[e.a,e.b,e.c],d=0;3>d;d++)if(e[d]===e[(d+1)%3]){a.push(g);break}for(g=a.length-1;0<=g;g--)for(e= [...]
+1),c=0,f=this.faceVertexUvs.length;c<f;c++)this.faceVertexUvs[c].splice(e,1);g=this.vertices.length-b.length;this.vertices=b;return g},sortFacesByMaterialIndex:function(){for(var a=this.faces,b=a.length,c=0;c<b;c++)a[c]._id=c;a.sort(function(a,b){return a.materialIndex-b.materialIndex});var d=this.faceVertexUvs[0],e=this.faceVertexUvs[1],g,f;d&&d.length===b&&(g=[]);e&&e.length===b&&(f=[]);for(c=0;c<b;c++){var h=a[c]._id;g&&g.push(d[h]);f&&f.push(e[h])}g&&(this.faceVertexUvs[0]=g);f&&(thi [...]
+f)},toJSON:function(){function a(a,b,c){return c?a|1<<b:a&~(1<<b)}function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void 0!==k[b])return k[b];k[b]=l.length/3;l.push(a.x,a.y,a.z);return k[b]}function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void 0!==p[b])return p[b];p[b]=m.length;m.push(a.getHex());return p[b]}function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==q[b])return q[b];q[b]=n.length/2;n.push(a.x,a.y);return q[b]}var e={metadata:{versi [...]
+generator:"Geometry.toJSON"}};e.uuid=this.uuid;e.type=this.type;""!==this.name&&(e.name=this.name);if(void 0!==this.parameters){var g=this.parameters,f;for(f in g)void 0!==g[f]&&(e[f]=g[f]);return e}g=[];for(f=0;f<this.vertices.length;f++){var h=this.vertices[f];g.push(h.x,h.y,h.z)}var h=[],l=[],k={},m=[],p={},n=[],q={};for(f=0;f<this.faces.length;f++){var s=this.faces[f],t=void 0!==this.faceVertexUvs[0][f],v=0<s.normal.length(),u=0<s.vertexNormals.length,w=1!==s.color.r||1!==s.color.g|| [...]
+D=0<s.vertexColors.length,x=0,x=a(x,0,0),x=a(x,1,!1),x=a(x,2,!1),x=a(x,3,t),x=a(x,4,v),x=a(x,5,u),x=a(x,6,w),x=a(x,7,D);h.push(x);h.push(s.a,s.b,s.c);t&&(t=this.faceVertexUvs[0][f],h.push(d(t[0]),d(t[1]),d(t[2])));v&&h.push(b(s.normal));u&&(v=s.vertexNormals,h.push(b(v[0]),b(v[1]),b(v[2])));w&&h.push(c(s.color));D&&(s=s.vertexColors,h.push(c(s[0]),c(s[1]),c(s[2])))}e.data={};e.data.vertices=g;e.data.normals=l;0<m.length&&(e.data.colors=m);0<n.length&&(e.data.uvs=[n]);e.data.faces=h;retur [...]
+copy:function(a){this.vertices=[];this.faces=[];this.faceVertexUvs=[[]];for(var b=a.vertices,c=0,d=b.length;c<d;c++)this.vertices.push(b[c].clone());b=a.faces;c=0;for(d=b.length;c<d;c++)this.faces.push(b[c].clone());c=0;for(d=a.faceVertexUvs.length;c<d;c++){b=a.faceVertexUvs[c];void 0===this.faceVertexUvs[c]&&(this.faceVertexUvs[c]=[]);for(var e=0,g=b.length;e<g;e++){for(var f=b[e],h=[],l=0,k=f.length;l<k;l++)h.push(f[l].clone());this.faceVertexUvs[c].push(h)}}return this},dispose:functi [...]
+THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype);THREE.GeometryIdCount=0;
+THREE.DirectGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="DirectGeometry";this.indices=[];this.vertices=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.groups=[];this.morphTargets={};this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=!1};
+THREE.DirectGeometry.prototype={constructor:THREE.DirectGeometry,computeBoundingBox:THREE.Geometry.prototype.computeBoundingBox,computeBoundingSphere:THREE.Geometry.prototype.computeBoundingSphere,computeFaceNormals:function(){console.warn("THREE.DirectGeometry: computeFaceNormals() is not a method of this type of geometry.")},computeVertexNormals:function(){console.warn("THREE.DirectGeometry: computeVertexNormals() is not a method of this type of geometry.")},computeGroups:function(a){v [...]
+d;a=a.faces;for(var e=0;e<a.length;e++){var g=a[e];g.materialIndex!==d&&(d=g.materialIndex,void 0!==b&&(b.count=3*e-b.start,c.push(b)),b={start:3*e,materialIndex:d})}void 0!==b&&(b.count=3*e-b.start,c.push(b));this.groups=c},fromGeometry:function(a){var b=a.faces,c=a.vertices,d=a.faceVertexUvs,e=d[0]&&0<d[0].length,g=d[1]&&0<d[1].length,f=a.morphTargets,h=f.length;if(0<h){for(var l=[],k=0;k<h;k++)l[k]=[];this.morphTargets.position=l}var m=a.morphNormals,p=m.length;if(0<p){for(var n=[],k= [...]
+[];this.morphTargets.normal=n}for(var q=a.skinIndices,s=a.skinWeights,t=q.length===c.length,v=s.length===c.length,k=0;k<b.length;k++){var u=b[k];this.vertices.push(c[u.a],c[u.b],c[u.c]);var w=u.vertexNormals;3===w.length?this.normals.push(w[0],w[1],w[2]):(w=u.normal,this.normals.push(w,w,w));w=u.vertexColors;3===w.length?this.colors.push(w[0],w[1],w[2]):(w=u.color,this.colors.push(w,w,w));!0===e&&(w=d[0][k],void 0!==w?this.uvs.push(w[0],w[1],w[2]):(console.warn("THREE.DirectGeometry.from [...]
+k),this.uvs.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2)));!0===g&&(w=d[1][k],void 0!==w?this.uvs2.push(w[0],w[1],w[2]):(console.warn("THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ",k),this.uvs2.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2)));for(w=0;w<h;w++){var D=f[w].vertices;l[w].push(D[u.a],D[u.b],D[u.c])}for(w=0;w<p;w++)D=m[w].vertexNormals[k],n[w].push(D.a,D.b,D.c);t&&this.skinIndices.push(q[u.a],q[u.b],q[u.c]);v&&this.skinWeights.push(s[u. [...]
+s[u.c])}this.computeGroups(a);this.verticesNeedUpdate=a.verticesNeedUpdate;this.normalsNeedUpdate=a.normalsNeedUpdate;this.colorsNeedUpdate=a.colorsNeedUpdate;this.uvsNeedUpdate=a.uvsNeedUpdate;this.groupsNeedUpdate=a.groupsNeedUpdate;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.DirectGeometry.prototype);
+THREE.BufferGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes={};this.groups=[];this.boundingSphere=this.boundingBox=null;this.drawRange={start:0,count:Infinity}};
+THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,addIndex:function(a){console.warn("THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().");this.setIndex(a)},getIndex:function(){return this.index},setIndex:function(a){this.index=a},addAttribute:function(a,b,c){!1===b instanceof THREE.BufferAttribute&&!1===b instanceof THREE.InterleavedBufferAttribute?(console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.addAttribute(a,ne [...]
+c))):"index"===a?(console.warn("THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute."),this.setIndex(b)):this.attributes[a]=b},getAttribute:function(a){return this.attributes[a]},removeAttribute:function(a){delete this.attributes[a]},get drawcalls(){console.error("THREE.BufferGeometry: .drawcalls has been renamed to .groups.");return this.groups},get offsets(){console.warn("THREE.BufferGeometry: .offsets has been renamed to .groups.");return this.groups},addDrawCall:fu [...]
+b,c){void 0!==c&&console.warn("THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.");console.warn("THREE.BufferGeometry: .addDrawCall() is now .addGroup().");this.addGroup(a,b)},clearDrawCalls:function(){console.warn("THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().");this.clearGroups()},addGroup:function(a,b,c){this.groups.push({start:a,count:b,materialIndex:void 0!==c?c:0})},clearGroups:function(){this.groups=[]},setDrawRange:function(a,b){this.drawRange. [...]
+b},applyMatrix:function(a){var b=this.attributes.position;void 0!==b&&(a.applyToVector3Array(b.array),b.needsUpdate=!0);b=this.attributes.normal;void 0!==b&&((new THREE.Matrix3).getNormalMatrix(a).applyToVector3Array(b.array),b.needsUpdate=!0);null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere()},rotateX:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationX(b);this.applyMatrix(a);return this}}(),rotate [...]
+return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationY(b);this.applyMatrix(a);return this}}(),rotateZ:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.makeRotationZ(b);this.applyMatrix(a);return this}}(),translate:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeTranslation(b,c,d);this.applyMatrix(a);return this}}(),scale:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeScale(b,c,d);this.ap [...]
+return this}}(),lookAt:function(){var a;return function(b){void 0===a&&(a=new THREE.Object3D);a.lookAt(b);a.updateMatrix();this.applyMatrix(a.matrix)}}(),center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.translate(a.x,a.y,a.z);return a},setFromObject:function(a){var b=a.geometry;if(a instanceof THREE.Points||a instanceof THREE.Line){a=new THREE.Float32Attribute(3*b.vertices.length,3);var c=new THREE.Float32Attribute(3*b.colors.length,3);this.addAtt [...]
+a.copyVector3sArray(b.vertices));this.addAttribute("color",c.copyColorsArray(b.colors));b.lineDistances&&b.lineDistances.length===b.vertices.length&&(a=new THREE.Float32Attribute(b.lineDistances.length,1),this.addAttribute("lineDistance",a.copyArray(b.lineDistances)));null!==b.boundingSphere&&(this.boundingSphere=b.boundingSphere.clone());null!==b.boundingBox&&(this.boundingBox=b.boundingBox.clone())}else a instanceof THREE.Mesh&&b instanceof THREE.Geometry&&this.fromGeometry(b);return t [...]
+a.geometry;if(a instanceof THREE.Mesh){var c=b.__directGeometry;if(void 0===c)return this.fromGeometry(b);c.verticesNeedUpdate=b.verticesNeedUpdate;c.normalsNeedUpdate=b.normalsNeedUpdate;c.colorsNeedUpdate=b.colorsNeedUpdate;c.uvsNeedUpdate=b.uvsNeedUpdate;c.groupsNeedUpdate=b.groupsNeedUpdate;b.verticesNeedUpdate=!1;b.normalsNeedUpdate=!1;b.colorsNeedUpdate=!1;b.uvsNeedUpdate=!1;b.groupsNeedUpdate=!1;b=c}!0===b.verticesNeedUpdate&&(c=this.attributes.position,void 0!==c&&(c.copyVector3s [...]
+c.needsUpdate=!0),b.verticesNeedUpdate=!1);!0===b.normalsNeedUpdate&&(c=this.attributes.normal,void 0!==c&&(c.copyVector3sArray(b.normals),c.needsUpdate=!0),b.normalsNeedUpdate=!1);!0===b.colorsNeedUpdate&&(c=this.attributes.color,void 0!==c&&(c.copyColorsArray(b.colors),c.needsUpdate=!0),b.colorsNeedUpdate=!1);b.uvsNeedUpdate&&(c=this.attributes.uv,void 0!==c&&(c.copyVector2sArray(b.uvs),c.needsUpdate=!0),b.uvsNeedUpdate=!1);b.lineDistancesNeedUpdate&&(c=this.attributes.lineDistance,voi [...]
+(c.copyArray(b.lineDistances),c.needsUpdate=!0),b.lineDistancesNeedUpdate=!1);b.groupsNeedUpdate&&(b.computeGroups(a.geometry),this.groups=b.groups,b.groupsNeedUpdate=!1);return this},fromGeometry:function(a){a.__directGeometry=(new THREE.DirectGeometry).fromGeometry(a);return this.fromDirectGeometry(a.__directGeometry)},fromDirectGeometry:function(a){var b=new Float32Array(3*a.vertices.length);this.addAttribute("position",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.vertices));0 [...]
+(b=new Float32Array(3*a.normals.length),this.addAttribute("normal",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.normals)));0<a.colors.length&&(b=new Float32Array(3*a.colors.length),this.addAttribute("color",(new THREE.BufferAttribute(b,3)).copyColorsArray(a.colors)));0<a.uvs.length&&(b=new Float32Array(2*a.uvs.length),this.addAttribute("uv",(new THREE.BufferAttribute(b,2)).copyVector2sArray(a.uvs)));0<a.uvs2.length&&(b=new Float32Array(2*a.uvs2.length),this.addAttribute("uv2",(ne [...]
+2)).copyVector2sArray(a.uvs2)));0<a.indices.length&&(b=new (65535<a.vertices.length?Uint32Array:Uint16Array)(3*a.indices.length),this.setIndex((new THREE.BufferAttribute(b,1)).copyIndicesArray(a.indices)));this.groups=a.groups;for(var c in a.morphTargets){for(var b=[],d=a.morphTargets[c],e=0,g=d.length;e<g;e++){var f=d[e],h=new THREE.Float32Attribute(3*f.length,3);b.push(h.copyVector3sArray(f))}this.morphAttributes[c]=b}0<a.skinIndices.length&&(c=new THREE.Float32Attribute(4*a.skinIndice [...]
+4),this.addAttribute("skinIndex",c.copyVector4sArray(a.skinIndices)));0<a.skinWeights.length&&(c=new THREE.Float32Attribute(4*a.skinWeights.length,4),this.addAttribute("skinWeight",c.copyVector4sArray(a.skinWeights)));null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());return this},computeBoundingBox:function(){var a=new THREE.Vector3;return function(){null===this.boundingBox&&(this.boundingBox=new THREE.B [...]
+this.attributes.position.array;if(b){var c=this.boundingBox;c.makeEmpty();for(var d=0,e=b.length;d<e;d+=3)a.fromArray(b,d),c.expandByPoint(a)}if(void 0===b||0===b.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0);(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.',this)}}(),compute [...]
+new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,e=0,g=c.length;e<g;e+=3)b.fromArray(c,e),a.expandByPoint(b);a.center(d);for(var f=0,e=0,g=c.length;e<g;e+=3)b.fromArray(c,e),f=Math.max(f,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(f);isNaN(this.boundingSphere.radius)&&console.error('THREE.BufferGeometry.compu [...]
+this)}}}(),computeFaceNormals:function(){},computeVertexNormals:function(){var a=this.index,b=this.attributes,c=this.groups;if(b.position){var d=b.position.array;if(void 0===b.normal)this.addAttribute("normal",new THREE.BufferAttribute(new Float32Array(d.length),3));else for(var e=b.normal.array,g=0,f=e.length;g<f;g++)e[g]=0;var e=b.normal.array,h,l,k,m=new THREE.Vector3,p=new THREE.Vector3,n=new THREE.Vector3,q=new THREE.Vector3,s=new THREE.Vector3;if(a){a=a.array;0===c.length&&this.add [...]
+for(var t=0,v=c.length;t<v;++t)for(g=c[t],f=g.start,h=g.count,g=f,f+=h;g<f;g+=3)h=3*a[g+0],l=3*a[g+1],k=3*a[g+2],m.fromArray(d,h),p.fromArray(d,l),n.fromArray(d,k),q.subVectors(n,p),s.subVectors(m,p),q.cross(s),e[h]+=q.x,e[h+1]+=q.y,e[h+2]+=q.z,e[l]+=q.x,e[l+1]+=q.y,e[l+2]+=q.z,e[k]+=q.x,e[k+1]+=q.y,e[k+2]+=q.z}else for(g=0,f=d.length;g<f;g+=9)m.fromArray(d,g),p.fromArray(d,g+3),n.fromArray(d,g+6),q.subVectors(n,p),s.subVectors(m,p),q.cross(s),e[g]=q.x,e[g+1]=q.y,e[g+2]=q.z,e[g+3]=q.x,e[ [...]
+e[g+5]=q.z,e[g+6]=q.x,e[g+7]=q.y,e[g+8]=q.z;this.normalizeNormals();b.normal.needsUpdate=!0}},computeTangents:function(){console.warn("THREE.BufferGeometry: .computeTangents() has been removed.")},computeOffsets:function(a){console.warn("THREE.BufferGeometry: .computeOffsets() has been removed.")},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.",a);else{void 0===b&&(b=0);var c=thi [...]
+d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,g=a.attributes[d],f=g.array,h=0,g=g.itemSize*b;h<f.length;h++,g++)e[g]=f[h];return this}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,g=a.length;e<g;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},toJSON:function(){var a={metadata:{version:4.4,type:"BufferGeometry",generator:"BufferGeometry.toJSON"}};a.uuid=this.uuid;a.type=this.type;""!==this.name&&(a.name [...]
+if(void 0!==this.parameters){var b=this.parameters,c;for(c in b)void 0!==b[c]&&(a[c]=b[c]);return a}a.data={attributes:{}};var d=this.index;null!==d&&(b=Array.prototype.slice.call(d.array),a.data.index={type:d.array.constructor.name,array:b});d=this.attributes;for(c in d){var e=d[c],b=Array.prototype.slice.call(e.array);a.data.attributes[c]={itemSize:e.itemSize,type:e.array.constructor.name,array:b}}c=this.groups;0<c.length&&(a.data.groups=JSON.parse(JSON.stringify(c)));c=this.boundingSp [...]
+c&&(a.data.boundingSphere={center:c.center.toArray(),radius:c.radius});return a},clone:function(){return(new this.constructor).copy(this)},copy:function(a){var b=a.index;null!==b&&this.setIndex(b.clone());var b=a.attributes,c;for(c in b)this.addAttribute(c,b[c].clone());a=a.groups;c=0;for(b=a.length;c<b;c++){var d=a[c];this.addGroup(d.start,d.count)}return this},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype);
+THREE.BufferGeometry.MaxIndex=65535;THREE.InstancedBufferGeometry=function(){THREE.BufferGeometry.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0};THREE.InstancedBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.InstancedBufferGeometry.prototype.constructor=THREE.InstancedBufferGeometry;THREE.InstancedBufferGeometry.prototype.addGroup=function(a,b,c){this.groups.push({start:a,count:b,instances:c})};
+THREE.InstancedBufferGeometry.prototype.copy=function(a){var b=a.index;null!==b&&this.setIndex(b.clone());var b=a.attributes,c;for(c in b)this.addAttribute(c,b[c].clone());a=a.groups;c=0;for(b=a.length;c<b;c++){var d=a[c];this.addGroup(d.start,d.count,d.instances)}return this};THREE.EventDispatcher.prototype.apply(THREE.InstancedBufferGeometry.prototype);
+THREE.AnimationAction=function(a,b,c,d,e){if(void 0===a)throw Error("clip is null");this.clip=a;this.localRoot=null;this.startTime=b||0;this.timeScale=c||1;this.weight=d||1;this.loop=e||THREE.LoopRepeat;this.loopCount=0;this.enabled=!0;this.actionTime=-this.startTime;this.clipTime=0;this.propertyBindings=[]};
+THREE.AnimationAction.prototype={constructor:THREE.AnimationAction,setLocalRoot:function(a){this.localRoot=a;return this},updateTime:function(a){var b=this.clipTime,c=this.loopCount,d=this.clip.duration;this.actionTime+=a;if(this.loop===THREE.LoopOnce)return this.loopCount=0,this.clipTime=Math.min(Math.max(this.actionTime,0),d),this.clipTime!==b&&(this.clipTime===d?this.mixer.dispatchEvent({type:"finished",action:this,direction:1}):0===this.clipTime&&this.mixer.dispatchEvent({type:"finis [...]
+direction:-1})),this.clipTime;this.loopCount=Math.floor(this.actionTime/d);a=this.actionTime-this.loopCount*d;a%=d;this.loop==THREE.LoopPingPong&&1===Math.abs(this.loopCount%2)&&(a=d-a);this.clipTime=a;this.loopCount!==c&&this.mixer.dispatchEvent({type:"loop",action:this,loopDelta:this.loopCount-this.loopCount});return this.clipTime},syncWith:function(a){this.actionTime=a.actionTime;this.timeScale=a.timeScale;return this},warpToDuration:function(a){this.timeScale=this.clip.duration/a;ret [...]
+init:function(a){this.clipTime=a-this.startTime;return this},update:function(a){this.updateTime(a);return this.clip.getAt(this.clipTime)},getTimeScaleAt:function(a){return this.timeScale.getAt?this.timeScale.getAt(a):this.timeScale},getWeightAt:function(a){return this.weight.getAt?this.weight.getAt(a):this.weight}};
+THREE.AnimationClip=function(a,b,c){this.name=a;this.tracks=c;this.duration=void 0!==b?b:-1;if(0>this.duration)for(a=0;a<this.tracks.length;a++)b=this.tracks[a],this.duration=Math.max(b.keys[b.keys.length-1].time);this.trim();this.optimize();this.results=[]};
+THREE.AnimationClip.prototype={constructor:THREE.AnimationClip,getAt:function(a){a=Math.max(0,Math.min(a,this.duration));for(var b=0;b<this.tracks.length;b++)this.results[b]=this.tracks[b].getAt(a);return this.results},trim:function(){for(var a=0;a<this.tracks.length;a++)this.tracks[a].trim(0,this.duration);return this},optimize:function(){for(var a=0;a<this.tracks.length;a++)this.tracks[a].optimize();return this}};
+THREE.AnimationClip.CreateFromMorphTargetSequence=function(a,b,c){for(var d=b.length,e=[],g=0;g<d;g++){var f=[];f.push({time:(g+d-1)%d,value:0});f.push({time:g,value:1});f.push({time:(g+1)%d,value:0});f.sort(THREE.KeyframeTrack.keyComparer);0===f[0].time&&f.push({time:d,value:f[0].value});e.push((new THREE.NumberKeyframeTrack(".morphTargetInfluences["+b[g].name+"]",f)).scale(1/c))}return new THREE.AnimationClip(a,-1,e)};
+THREE.AnimationClip.findByName=function(a,b){for(var c=0;c<a.length;c++)if(a[c].name===b)return a[c];return null};THREE.AnimationClip.CreateClipsFromMorphTargetSequences=function(a,b){for(var c={},d=/^([\w-]*?)([\d]+)$/,e=0,g=a.length;e<g;e++){var f=a[e],h=f.name.match(d);if(h&&1<h.length){var l=h[1];(h=c[l])||(c[l]=h=[]);h.push(f)}}d=[];for(l in c)d.push(THREE.AnimationClip.CreateFromMorphTargetSequence(l,c[l],b));return d};
+THREE.AnimationClip.parse=function(a){for(var b=[],c=0;c<a.tracks.length;c++)b.push(THREE.KeyframeTrack.parse(a.tracks[c]).scale(1/a.fps));return new THREE.AnimationClip(a.name,a.duration,b)};
+THREE.AnimationClip.parseAnimation=function(a,b,c){if(!a)return console.error("  no animation in JSONLoader data"),null;var d=function(a,b,c,d,e){for(var g=[],f=0;f<b.length;f++){var h=b[f];void 0!==h[c]&&g.push({time:h.time,value:e(h)})}return 0<g.length?new d(a,g):null},e=[],g=a.name||"default",f=a.length||-1,h=a.fps||30;a=a.hierarchy||[];for(var l=0;l<a.length;l++){var k=a[l].keys;if(k&&0!=k.length)if(k[0].morphTargets){for(var f={},m=0;m<k.length;m++)if(k[m].morphTargets)for(var p=0; [...]
+-1;for(var n in f){for(var q=[],p=0;p<k[m].morphTargets.length;p++){var s=k[m];q.push({time:s.time,value:s.morphTarget===n?1:0})}e.push(new THREE.NumberKeyframeTrack(c+".morphTargetInfluence["+n+"]",q))}f=f.length*(h||1)}else m=c+".bones["+b[l].name+"]",(p=d(m+".position",k,"pos",THREE.VectorKeyframeTrack,function(a){return(new THREE.Vector3).fromArray(a.pos)}))&&e.push(p),(p=d(m+".quaternion",k,"rot",THREE.QuaternionKeyframeTrack,function(a){return a.rot.slerp?a.rot.clone():(new THREE.Q [...]
+e.push(p),(k=d(m+".scale",k,"scl",THREE.VectorKeyframeTrack,function(a){return(new THREE.Vector3).fromArray(a.scl)}))&&e.push(k)}return 0===e.length?null:new THREE.AnimationClip(g,f,e)};THREE.AnimationMixer=function(a){this.root=a;this.time=0;this.timeScale=1;this.actions=[];this.propertyBindingMap={}};
+THREE.AnimationMixer.prototype={constructor:THREE.AnimationMixer,addAction:function(a){this.actions.push(a);a.init(this.time);a.mixer=this;for(var b=a.clip.tracks,c=a.localRoot||this.root,d=0;d<b.length;d++){var e=b[d],g=c.uuid+"-"+e.name,f=this.propertyBindingMap[g];void 0===f&&(f=new THREE.PropertyBinding(c,e.name),this.propertyBindingMap[g]=f);a.propertyBindings.push(f);f.referenceCount+=1}},removeAllActions:function(){for(var a=0;a<this.actions.length;a++)this.actions[a].mixer=null;f [...]
+this.actions=[];this.propertyBindingMap={};return this},removeAction:function(a){var b=this.actions.indexOf(a);-1!==b&&(this.actions.splice(b,1),a.mixer=null);b=a.localRoot||this.root;a=a.clip.tracks;for(var c=0;c<a.length;c++){var d=b.uuid+"-"+a[c].name,e=this.propertyBindingMap[d];e.referenceCount-=1;0>=e.referenceCount&&(e.unbind(),delete this.propertyBindingMap[d])}return this},findActionByName:function(a){for(var b=0;b<this.actions.length;b++)if(this.actions[b].name===a)return this. [...]
+return null},play:function(a,b){a.startTime=this.time;this.addAction(a);return this},fadeOut:function(a,b){var c=[];c.push({time:this.time,value:1});c.push({time:this.time+b,value:0});a.weight=new THREE.NumberKeyframeTrack("weight",c);return this},fadeIn:function(a,b){var c=[];c.push({time:this.time,value:0});c.push({time:this.time+b,value:1});a.weight=new THREE.NumberKeyframeTrack("weight",c);return this},warp:function(a,b,c,d){var e=[];e.push({time:this.time,value:b});e.push({time:this [...]
+a.timeScale=new THREE.NumberKeyframeTrack("timeScale",e);return this},crossFade:function(a,b,c,d){this.fadeOut(a,c);this.fadeIn(b,c);if(d){d=a.clip.duration/b.clip.duration;var e=1/d;this.warp(a,1,d,c);this.warp(b,e,1,c)}return this},update:function(a){a*=this.timeScale;this.time+=a;for(var b=0;b<this.actions.length;b++){var c=this.actions[b],d=c.getWeightAt(this.time),e=c.getTimeScaleAt(this.time),e=c.update(a*e);if(!(0>=c.weight)&&c.enabled)for(var g=0;g<e.length;g++)c.propertyBindings [...]
+d)}for(var f in this.propertyBindingMap)this.propertyBindingMap[f].apply();return this}};THREE.EventDispatcher.prototype.apply(THREE.AnimationMixer.prototype);
+THREE.AnimationUtils={getEqualsFunc:function(a){return a.equals?function(a,c){return a.equals(c)}:function(a,c){return a===c}},clone:function(a){if("object"===typeof a){if(a.clone)return a.clone();console.error("can not figure out how to copy exemplarValue",a)}return a},lerp:function(a,b,c,d){return THREE.AnimationUtils.getLerpFunc(a,d)(a,b,c)},lerp_object:function(a,b,c){return a.lerp(b,c)},slerp_object:function(a,b,c){return a.slerp(b,c)},lerp_number:function(a,b,c){return a*(1-c)+b*c} [...]
+b,c){return.5>c?a:b},lerp_boolean_immediate:function(a,b,c){return a},lerp_string:function(a,b,c){return.5>c?a:b},lerp_string_immediate:function(a,b,c){return a},getLerpFunc:function(a,b){if(void 0===a||null===a)throw Error("examplarValue is null");switch(typeof a){case "object":if(a.lerp)return THREE.AnimationUtils.lerp_object;if(a.slerp)return THREE.AnimationUtils.slerp_object;break;case "number":return THREE.AnimationUtils.lerp_number;case "boolean":return b?THREE.AnimationUtils.lerp_ [...]
+case "string":return b?THREE.AnimationUtils.lerp_string:THREE.AnimationUtils.lerp_string_immediate}}};THREE.KeyframeTrack=function(a,b){if(void 0===a)throw Error("track name is undefined");if(void 0===b||0===b.length)throw Error("no keys in track named "+a);this.name=a;this.keys=b;this.lastIndex=0;this.validate();this.optimize()};
+THREE.KeyframeTrack.prototype={constructor:THREE.KeyframeTrack,getAt:function(a){for(;this.lastIndex<this.keys.length&&a>=this.keys[this.lastIndex].time;)this.lastIndex++;for(;0<this.lastIndex&&a<this.keys[this.lastIndex-1].time;)this.lastIndex--;if(this.lastIndex>=this.keys.length)return this.setResult(this.keys[this.keys.length-1].value),this.result;if(0===this.lastIndex)return this.setResult(this.keys[0].value),this.result;var b=this.keys[this.lastIndex-1];this.setResult(b.value);if(b [...]
+var c=this.keys[this.lastIndex];return this.result=this.lerpValues(this.result,c.value,(a-b.time)/(c.time-b.time))},shift:function(a){if(0!==a)for(var b=0;b<this.keys.length;b++)this.keys[b].time+=a;return this},scale:function(a){if(1!==a)for(var b=0;b<this.keys.length;b++)this.keys[b].time*=a;return this},trim:function(a,b){for(var c=0,d=1;d<this.keys.length;d++)this.keys[d]<=a&&c++;for(var e=0,d=this.keys.length-2;0<d;d++)if(this.keys[d]>=b)e++;else break;0<c+e&&(this.keys=this.keys.sp [...]
+e-c));return this},validate:function(){var a=null;if(0===this.keys.length)console.error("  track is empty, no keys",this);else{for(var b=0;b<this.keys.length;b++){var c=this.keys[b];if(!c){console.error("  key is null in track",this,b);return}if("number"!==typeof c.time||isNaN(c.time)){console.error("  key.time is not a valid number",this,b,c);return}if(void 0===c.value||null===c.value){console.error("  key.value is null in track",this,b,c);return}if(a&&a.time>c.time){console.error("  ke [...]
+this,b,c,a);return}a=c}return this}},optimize:function(){var a=[],b=this.keys[0];a.push(b);THREE.AnimationUtils.getEqualsFunc(b.value);for(var c=1;c<this.keys.length-1;c++){var d=this.keys[c],e=this.keys[c+1];b.time===d.time||this.compareValues(b.value,d.value)&&this.compareValues(d.value,e.value)||(b.constantToNext=this.compareValues(b.value,d.value),a.push(d),b=d)}a.push(this.keys[this.keys.length-1]);this.keys=a;return this}};THREE.KeyframeTrack.keyComparer=function(a,b){return a.time [...]
+THREE.KeyframeTrack.parse=function(a){if(void 0===a.type)throw Error("track type undefined, can not parse");return THREE.KeyframeTrack.GetTrackTypeForTypeName(a.type).parse(a)};
+THREE.KeyframeTrack.GetTrackTypeForTypeName=function(a){switch(a.toLowerCase()){case "vector":case "vector2":case "vector3":case "vector4":return THREE.VectorKeyframeTrack;case "quaternion":return THREE.QuaternionKeyframeTrack;case "integer":case "scalar":case "double":case "float":case "number":return THREE.NumberKeyframeTrack;case "bool":case "boolean":return THREE.BooleanKeyframeTrack;case "string":return THREE.StringKeyframeTrack}throw Error("Unsupported typeName: "+a);};
+THREE.PropertyBinding=function(a,b){this.rootNode=a;this.trackName=b;this.referenceCount=0;this.originalValue=null;var c=THREE.PropertyBinding.parseTrackName(b);this.directoryName=c.directoryName;this.nodeName=c.nodeName;this.objectName=c.objectName;this.objectIndex=c.objectIndex;this.propertyName=c.propertyName;this.propertyIndex=c.propertyIndex;this.node=THREE.PropertyBinding.findNode(a,this.nodeName)||a;this.cumulativeValue=null;this.cumulativeWeight=0};
+THREE.PropertyBinding.prototype={constructor:THREE.PropertyBinding,reset:function(){this.cumulativeValue=null;this.cumulativeWeight=0},accumulate:function(a,b){this.isBound||this.bind();0===this.cumulativeWeight?0<b&&(null===this.cumulativeValue&&(this.cumulativeValue=THREE.AnimationUtils.clone(a)),this.cumulativeWeight=b):(this.cumulativeValue=this.lerpValue(this.cumulativeValue,a,b/(this.cumulativeWeight+b)),this.cumulativeWeight+=b)},unbind:function(){this.isBound&&(this.setValue(this [...]
+this.triggerDirty=this.equalsValue=this.lerpValue=this.getValue=this.setValue=null,this.isBound=!1)},bind:function(){if(!this.isBound){var a=this.node;if(a){if(this.objectName){if("materials"===this.objectName){if(!a.material){console.error("  can not bind to material as node does not have a material",this);return}if(!a.material.materials){console.error("  can not bind to material.materials as node.material does not have a materials array",this);return}a=a.material.materials}else if("bon [...]
+this);return}for(var a=a.skeleton.bones,b=0;b<a.length;b++)if(a[b].name===this.objectIndex){this.objectIndex=b;break}}else{if(void 0===a[this.objectName]){console.error("  can not bind to objectName of node, undefined",this);return}a=a[this.objectName]}if(void 0!==this.objectIndex){if(void 0===a[this.objectIndex]){console.error("  trying to bind to objectIndex of objectName, but is undefined:",this,a);return}a=a[this.objectIndex]}}var c=a[this.propertyName];if(c){if(void 0!==this.propert [...]
+this.propertyName)for(a.geometry||console.error("  can not bind to morphTargetInfluences becasuse node does not have a geometry",this),a.geometry.morphTargets||console.error("  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets",this),b=0;b<this.node.geometry.morphTargets.length;b++)if(a.geometry.morphTargets[b].name===this.propertyIndex){this.propertyIndex=b;break}this.setValue=function(a){return this.equalsValue(c[this.propertyIndex],a)?!1:(c[this [...]
+a,!0)};this.getValue=function(){return c[this.propertyIndex]}}else c.copy?(this.setValue=function(a){return this.equalsValue(c,a)?!1:(c.copy(a),!0)},this.getValue=function(){return c}):(this.setValue=function(b){return this.equalsValue(a[this.propertyName],b)?!1:(a[this.propertyName]=b,!0)},this.getValue=function(){return a[this.propertyName]});void 0!==a.needsUpdate?this.triggerDirty=function(){this.node.needsUpdate=!0}:void 0!==a.matrixWorldNeedsUpdate&&(this.triggerDirty=function(){a. [...]
+!0});this.originalValue=this.getValue();this.equalsValue=THREE.AnimationUtils.getEqualsFunc(this.originalValue);this.lerpValue=THREE.AnimationUtils.getLerpFunc(this.originalValue,!0);this.isBound=!0}else console.error("  trying to update property for track: "+this.nodeName+"."+this.propertyName+" but it wasn't found.",a)}else console.error("  trying to update node for track: "+this.trackName+" but it wasn't found.")}},apply:function(){this.isBound||this.bind();if(0<this.cumulativeWeight) [...]
+1-this.cumulativeWeight;this.cumulativeValue=this.lerpValue(this.cumulativeValue,this.originalValue,a/(this.cumulativeWeight+a))}this.setValue(this.cumulativeValue)&&this.triggerDirty&&this.triggerDirty();this.cumulativeValue=null;this.cumulativeWeight=0}}};
+THREE.PropertyBinding.parseTrackName=function(a){var b=/^(([\w]+\/)*)([\w-\d]+)?(\.([\w]+)(\[([\w\d\[\]\_. ]+)\])?)?(\.([\w.]+)(\[([\w\d\[\]\_. ]+)\])?)$/,c=b.exec(a);if(!c)throw Error("cannot parse trackName at all: "+a);c.index===b.lastIndex&&b.lastIndex++;b={directoryName:c[1],nodeName:c[3],objectName:c[5],objectIndex:c[7],propertyName:c[9],propertyIndex:c[11]};if(null===b.propertyName||0===b.propertyName.length)throw Error("can not parse propertyName from trackName: "+a);return b};
+THREE.PropertyBinding.findNode=function(a,b){function c(a){for(var c=0;c<a.bones.length;c++){var d=a.bones[c];if(d.name===b)return d}return null}function d(a){for(var c=0;c<a.length;c++){var e=a[c];if(e.name===b||e.uuid===b||(e=d(e.children)))return e}return null}if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a;if(a.skeleton){var e=c(a.skeleton);if(e)return e}return a.children&&(e=d(a.children))?e:null};
+THREE.VectorKeyframeTrack=function(a,b){THREE.KeyframeTrack.call(this,a,b);this.result=this.keys[0].value.clone()};THREE.VectorKeyframeTrack.prototype=Object.create(THREE.KeyframeTrack.prototype);THREE.VectorKeyframeTrack.prototype.constructor=THREE.VectorKeyframeTrack;THREE.VectorKeyframeTrack.prototype.setResult=function(a){this.result.copy(a)};THREE.VectorKeyframeTrack.prototype.lerpValues=function(a,b,c){return a.lerp(b,c)};THREE.VectorKeyframeTrack.prototype.compareValues=function(a [...]
+THREE.VectorKeyframeTrack.prototype.clone=function(){for(var a=[],b=0;b<this.keys.length;b++){var c=this.keys[b];a.push({time:c.time,value:c.value.clone()})}return new THREE.VectorKeyframeTrack(this.name,a)};THREE.VectorKeyframeTrack.parse=function(a){for(var b=THREE["Vector"+a.keys[0].value.length],c=[],d=0;d<a.keys.length;d++){var e=a.keys[d];c.push({value:(new b).fromArray(e.value),time:e.time})}return new THREE.VectorKeyframeTrack(a.name,c)};
+THREE.QuaternionKeyframeTrack=function(a,b){THREE.KeyframeTrack.call(this,a,b);this.result=this.keys[0].value.clone()};THREE.QuaternionKeyframeTrack.prototype=Object.create(THREE.KeyframeTrack.prototype);THREE.QuaternionKeyframeTrack.prototype.constructor=THREE.QuaternionKeyframeTrack;THREE.QuaternionKeyframeTrack.prototype.setResult=function(a){this.result.copy(a)};THREE.QuaternionKeyframeTrack.prototype.lerpValues=function(a,b,c){return a.slerp(b,c)};
+THREE.QuaternionKeyframeTrack.prototype.compareValues=function(a,b){return a.equals(b)};THREE.QuaternionKeyframeTrack.prototype.multiply=function(a){for(var b=0;b<this.keys.length;b++)this.keys[b].value.multiply(a);return this};THREE.QuaternionKeyframeTrack.prototype.clone=function(){for(var a=[],b=0;b<this.keys.length;b++){var c=this.keys[b];a.push({time:c.time,value:c.value.clone()})}return new THREE.QuaternionKeyframeTrack(this.name,a)};
+THREE.QuaternionKeyframeTrack.parse=function(a){for(var b=[],c=0;c<a.keys.length;c++){var d=a.keys[c];b.push({value:(new THREE.Quaternion).fromArray(d.value),time:d.time})}return new THREE.QuaternionKeyframeTrack(a.name,b)};THREE.StringKeyframeTrack=function(a,b){THREE.KeyframeTrack.call(this,a,b);this.result=this.keys[0].value};THREE.StringKeyframeTrack.prototype=Object.create(THREE.KeyframeTrack.prototype);THREE.StringKeyframeTrack.prototype.constructor=THREE.StringKeyframeTrack;
+THREE.StringKeyframeTrack.prototype.setResult=function(a){this.result=a};THREE.StringKeyframeTrack.prototype.lerpValues=function(a,b,c){return 1>c?a:b};THREE.StringKeyframeTrack.prototype.compareValues=function(a,b){return a===b};THREE.StringKeyframeTrack.prototype.clone=function(){for(var a=[],b=0;b<this.keys.length;b++){var c=this.keys[b];a.push({time:c.time,value:c.value})}return new THREE.StringKeyframeTrack(this.name,a)};
+THREE.StringKeyframeTrack.parse=function(a){return new THREE.StringKeyframeTrack(a.name,a.keys)};THREE.BooleanKeyframeTrack=function(a,b){THREE.KeyframeTrack.call(this,a,b);this.result=this.keys[0].value};THREE.BooleanKeyframeTrack.prototype=Object.create(THREE.KeyframeTrack.prototype);THREE.BooleanKeyframeTrack.prototype.constructor=THREE.BooleanKeyframeTrack;THREE.BooleanKeyframeTrack.prototype.setResult=function(a){this.result=a};
+THREE.BooleanKeyframeTrack.prototype.lerpValues=function(a,b,c){return 1>c?a:b};THREE.BooleanKeyframeTrack.prototype.compareValues=function(a,b){return a===b};THREE.BooleanKeyframeTrack.prototype.clone=function(){for(var a=[],b=0;b<this.keys.length;b++){var c=this.keys[b];a.push({time:c.time,value:c.value})}return new THREE.BooleanKeyframeTrack(this.name,a)};THREE.BooleanKeyframeTrack.parse=function(a){return new THREE.BooleanKeyframeTrack(a.name,a.keys)};
+THREE.NumberKeyframeTrack=function(a,b){THREE.KeyframeTrack.call(this,a,b);this.result=this.keys[0].value};THREE.NumberKeyframeTrack.prototype=Object.create(THREE.KeyframeTrack.prototype);THREE.NumberKeyframeTrack.prototype.constructor=THREE.NumberKeyframeTrack;THREE.NumberKeyframeTrack.prototype.setResult=function(a){this.result=a};THREE.NumberKeyframeTrack.prototype.lerpValues=function(a,b,c){return a*(1-c)+b*c};THREE.NumberKeyframeTrack.prototype.compareValues=function(a,b){return a===b};
+THREE.NumberKeyframeTrack.prototype.clone=function(){for(var a=[],b=0;b<this.keys.length;b++){var c=this.keys[b];a.push({time:c.time,value:c.value})}return new THREE.NumberKeyframeTrack(this.name,a)};THREE.NumberKeyframeTrack.parse=function(a){return new THREE.NumberKeyframeTrack(a.name,a.keys)};THREE.Camera=function(){THREE.Object3D.call(this);this.type="Camera";this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE. [...]
+THREE.Camera.prototype.constructor=THREE.Camera;THREE.Camera.prototype.getWorldDirection=function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,-1).applyQuaternion(a)}}();THREE.Camera.prototype.lookAt=function(){var a=new THREE.Matrix4;return function(b){a.lookAt(this.position,b,this.up);this.quaternion.setFromRotationMatrix(a)}}();THREE.Camera.prototype.clone=function(){return(new this.constructor).copy(this)};
+THREE.Camera.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a);this.matrixWorldInverse.copy(a.matrixWorldInverse);this.projectionMatrix.copy(a.projectionMatrix);return this};
+THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);this.type="CubeCamera";var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var g=new THREE.PerspectiveCamera(90,1,a,b);g.up.set(0,0,1);g.lookAt(new THREE.Vector3(0,1,0));this.add(g);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,-1);f.lookAt(new THREE.Vector [...]
+this.add(f);var h=new THREE.PerspectiveCamera(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new THREE.Vector3(0,0,1));this.add(h);var l=new THREE.PerspectiveCamera(90,1,a,b);l.up.set(0,-1,0);l.lookAt(new THREE.Vector3(0,0,-1));this.add(l);this.renderTarget=new THREE.WebGLRenderTargetCube(c,c,{format:THREE.RGBFormat,magFilter:THREE.LinearFilter,minFilter:THREE.LinearFilter});this.updateCubeMap=function(a,b){null===this.parent&&this.updateMatrixWorld();var c=this.renderTarget,n=c.texture.generateMip [...]
+!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,g,c);c.activeCubeFace=3;a.render(b,f,c);c.activeCubeFace=4;a.render(b,h,c);c.texture.generateMipmaps=n;c.activeCubeFace=5;a.render(b,l,c);a.setRenderTarget(null)}};THREE.CubeCamera.prototype=Object.create(THREE.Object3D.prototype);THREE.CubeCamera.prototype.constructor=THREE.CubeCamera;
+THREE.OrthographicCamera=function(a,b,c,d,e,g){THREE.Camera.call(this);this.type="OrthographicCamera";this.zoom=1;this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:.1;this.far=void 0!==g?g:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=Object.create(THREE.Camera.prototype);THREE.OrthographicCamera.prototype.constructor=THREE.OrthographicCamera;
+THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){var a=(this.right-this.left)/(2*this.zoom),b=(this.top-this.bottom)/(2*this.zoom),c=(this.right+this.left)/2,d=(this.top+this.bottom)/2;this.projectionMatrix.makeOrthographic(c-a,c+a,d+b,d-b,this.near,this.far)};THREE.OrthographicCamera.prototype.copy=function(a){THREE.Camera.prototype.copy.call(this,a);this.left=a.left;this.right=a.right;this.top=a.top;this.bottom=a.bottom;this.near=a.near;this.far=a.far;this.zoom=a.zo [...]
+THREE.OrthographicCamera.prototype.toJSON=function(a){a=THREE.Object3D.prototype.toJSON.call(this,a);a.object.zoom=this.zoom;a.object.left=this.left;a.object.right=this.right;a.object.top=this.top;a.object.bottom=this.bottom;a.object.near=this.near;a.object.far=this.far;return a};THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.type="PerspectiveCamera";this.zoom=1;this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:.1;this.far=void 0!==d?d:2E3 [...]
+THREE.PerspectiveCamera.prototype=Object.create(THREE.Camera.prototype);THREE.PerspectiveCamera.prototype.constructor=THREE.PerspectiveCamera;THREE.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);this.fov=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,g){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=e;this.height=g;this.updateProjectionMatrix()};
+THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){var a=THREE.Math.radToDeg(2*Math.atan(Math.tan(.5*THREE.Math.degToRad(this.fov))/this.zoom));if(this.fullWidth){var b=this.fullWidth/this.fullHeight,a=Math.tan(THREE.Math.degToRad(.5*a))*this.near,c=-a,d=b*c,b=Math.abs(b*a-d),c=Math.abs(a-c);this.projectionMatrix.makeFrustum(d+this.x*b/this.fullWidth,d+(this.x+this.width)*b/this.fullWidth,a-(this.y+this.height)*c/this.fullHeight,a-this.y*c/this.fullHeight,this.near,this. [...]
+this.aspect,this.near,this.far)};THREE.PerspectiveCamera.prototype.copy=function(a){THREE.Camera.prototype.copy.call(this,a);this.fov=a.fov;this.aspect=a.aspect;this.near=a.near;this.far=a.far;this.zoom=a.zoom;return this};THREE.PerspectiveCamera.prototype.toJSON=function(a){a=THREE.Object3D.prototype.toJSON.call(this,a);a.object.zoom=this.zoom;a.object.fov=this.fov;a.object.aspect=this.aspect;a.object.near=this.near;a.object.far=this.far;return a};
+THREE.Light=function(a){THREE.Object3D.call(this);this.type="Light";this.color=new THREE.Color(a);this.receiveShadow=void 0};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.Light.prototype.constructor=THREE.Light;
+Object.defineProperties(THREE.Light.prototype,{onlyShadow:{set:function(a){console.warn("THREE.Light: .onlyShadow has been removed.")}},shadowCameraFov:{set:function(a){this.shadow.camera.fov=a}},shadowCameraLeft:{set:function(a){this.shadow.camera.left=a}},shadowCameraRight:{set:function(a){this.shadow.camera.right=a}},shadowCameraTop:{set:function(a){this.shadow.camera.top=a}},shadowCameraBottom:{set:function(a){this.shadow.camera.bottom=a}},shadowCameraNear:{set:function(a){this.shado [...]
+a}},shadowCameraFar:{set:function(a){this.shadow.camera.far=a}},shadowCameraVisible:{set:function(a){console.warn("THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow ) instead.")}},shadowBias:{set:function(a){this.shadow.bias=a}},shadowDarkness:{set:function(a){this.shadow.darkness=a}},shadowMapWidth:{set:function(a){this.shadow.mapSize.width=a}},shadowMapHeight:{set:function(a){this.shadow.mapSize.height=a}}});
+THREE.Light.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a);this.color.copy(a.color);return this};
+THREE.Light.prototype.toJSON=function(a){a=THREE.Object3D.prototype.toJSON.call(this,a);a.object.color=this.color.getHex();void 0!==this.groundColor&&(a.object.groundColor=this.groundColor.getHex());void 0!==this.intensity&&(a.object.intensity=this.intensity);void 0!==this.distance&&(a.object.distance=this.distance);void 0!==this.angle&&(a.object.angle=this.angle);void 0!==this.decay&&(a.object.decay=this.decay);void 0!==this.exponent&&(a.object.exponent=this.exponent);return a};
+THREE.LightShadow=function(a){this.camera=a;this.bias=0;this.darkness=1;this.mapSize=new THREE.Vector2(512,512);this.matrix=this.map=null};THREE.LightShadow.prototype={constructor:THREE.LightShadow,copy:function(a){this.camera=a.camera.clone();this.bias=a.bias;this.darkness=a.darkness;this.mapSize.copy(a.mapSize)},clone:function(){return(new this.constructor).copy(this)}};THREE.AmbientLight=function(a){THREE.Light.call(this,a);this.type="AmbientLight";this.castShadow=void 0};
+THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.type="DirectionalLight";this.position.set(0,1,0);this.updateMatrix();this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.shadow=new THREE.LightShadow(new THREE.OrthographicCamera(-500,500,500,-500,50,5E3))};THREE.DirectionalLight.prototype=Object.create(THREE.Light.prototype);
+THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;THREE.DirectionalLight.prototype.copy=function(a){THREE.Light.prototype.copy.call(this,a);this.intensity=a.intensity;this.target=a.target.clone();this.shadow=a.shadow.clone();return this};THREE.HemisphereLight=function(a,b,c){THREE.Light.call(this,a);this.type="HemisphereLight";this.castShadow=void 0;this.position.set(0,1,0);this.updateMatrix();this.groundColor=new THREE.Color(b);this.intensity=void 0!==c?c:1};
+THREE.HemisphereLight.prototype=Object.create(THREE.Light.prototype);THREE.HemisphereLight.prototype.constructor=THREE.HemisphereLight;THREE.HemisphereLight.prototype.copy=function(a){THREE.Light.prototype.copy.call(this,a);this.groundColor.copy(a.groundColor);this.intensity=a.intensity;return this};
+THREE.PointLight=function(a,b,c,d){THREE.Light.call(this,a);this.type="PointLight";this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.decay=void 0!==d?d:1;this.shadow=new THREE.LightShadow(new THREE.PerspectiveCamera(90,1,1,500))};THREE.PointLight.prototype=Object.create(THREE.Light.prototype);THREE.PointLight.prototype.constructor=THREE.PointLight;
+THREE.PointLight.prototype.copy=function(a){THREE.Light.prototype.copy.call(this,a);this.intensity=a.intensity;this.distance=a.distance;this.decay=a.decay;this.shadow=a.shadow.clone();return this};
+THREE.SpotLight=function(a,b,c,d,e,g){THREE.Light.call(this,a);this.type="SpotLight";this.position.set(0,1,0);this.updateMatrix();this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/3;this.exponent=void 0!==e?e:10;this.decay=void 0!==g?g:1;this.shadow=new THREE.LightShadow(new THREE.PerspectiveCamera(50,1,50,5E3))};THREE.SpotLight.prototype=Object.create(THREE.Light.prototype);THREE.SpotLight.prototype.constructor=THRE [...]
+THREE.SpotLight.prototype.copy=function(a){THREE.Light.prototype.copy.call(this,a);this.intensity=a.intensity;this.distance=a.distance;this.angle=a.angle;this.exponent=a.exponent;this.decay=a.decay;this.target=a.target.clone();this.shadow=a.shadow.clone();return this};THREE.Cache={enabled:!1,files:{},add:function(a,b){!1!==this.enabled&&(this.files[a]=b)},get:function(a){if(!1!==this.enabled)return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}};
+THREE.Loader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}};
+THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:void 0,extractUrlBase:function(a){a=a.split("/");if(1===a.length)return"./";a.pop();return a.join("/")+"/"},initMaterials:function(a,b,c){for(var d=[],e=0;e<a.length;++e)d[e]=this.createMaterial(a[e],b,c);return d},createMaterial:function(){var a,b,c;return function(d,e,g){function f(a,c,d,f,l){a=e+a;var k=THREE.Loader.Handlers.get(a);null!==k?a=k.load(a):(b.setCrossOrigin(g),a=b.load(a));void 0!==c&&(a.repeat.fromArray(c),1!== [...]
+THREE.RepeatWrapping),1!==c[1]&&(a.wrapT=THREE.RepeatWrapping));void 0!==d&&a.offset.fromArray(d);void 0!==f&&("repeat"===f[0]&&(a.wrapS=THREE.RepeatWrapping),"mirror"===f[0]&&(a.wrapS=THREE.MirroredRepeatWrapping),"repeat"===f[1]&&(a.wrapT=THREE.RepeatWrapping),"mirror"===f[1]&&(a.wrapT=THREE.MirroredRepeatWrapping));void 0!==l&&(a.anisotropy=l);c=THREE.Math.generateUUID();h[c]=a;return c}void 0===a&&(a=new THREE.Color);void 0===b&&(b=new THREE.TextureLoader);void 0===c&&(c=new THREE.Ma [...]
+var h={},l={uuid:THREE.Math.generateUUID(),type:"MeshLambertMaterial"},k;for(k in d){var m=d[k];switch(k){case "DbgColor":l.color=m;break;case "DbgIndex":case "opticalDensity":case "illumination":break;case "DbgName":l.name=m;break;case "blending":l.blending=THREE[m];break;case "colorDiffuse":l.color=a.fromArray(m).getHex();break;case "colorSpecular":l.specular=a.fromArray(m).getHex();break;case "colorEmissive":l.emissive=a.fromArray(m).getHex();break;case "specularCoef":l.shininess=m;br [...]
+m.toLowerCase()&&(l.type="MeshBasicMaterial");"phong"===m.toLowerCase()&&(l.type="MeshPhongMaterial");break;case "mapDiffuse":l.map=f(m,d.mapDiffuseRepeat,d.mapDiffuseOffset,d.mapDiffuseWrap,d.mapDiffuseAnisotropy);break;case "mapDiffuseRepeat":case "mapDiffuseOffset":case "mapDiffuseWrap":case "mapDiffuseAnisotropy":break;case "mapLight":l.lightMap=f(m,d.mapLightRepeat,d.mapLightOffset,d.mapLightWrap,d.mapLightAnisotropy);break;case "mapLightRepeat":case "mapLightOffset":case "mapLightW [...]
+case "mapAO":l.aoMap=f(m,d.mapAORepeat,d.mapAOOffset,d.mapAOWrap,d.mapAOAnisotropy);break;case "mapAORepeat":case "mapAOOffset":case "mapAOWrap":case "mapAOAnisotropy":break;case "mapBump":l.bumpMap=f(m,d.mapBumpRepeat,d.mapBumpOffset,d.mapBumpWrap,d.mapBumpAnisotropy);break;case "mapBumpScale":l.bumpScale=m;break;case "mapBumpRepeat":case "mapBumpOffset":case "mapBumpWrap":case "mapBumpAnisotropy":break;case "mapNormal":l.normalMap=f(m,d.mapNormalRepeat,d.mapNormalOffset,d.mapNormalWrap [...]
+break;case "mapNormalFactor":l.normalScale=[m,m];break;case "mapNormalRepeat":case "mapNormalOffset":case "mapNormalWrap":case "mapNormalAnisotropy":break;case "mapSpecular":l.specularMap=f(m,d.mapSpecularRepeat,d.mapSpecularOffset,d.mapSpecularWrap,d.mapSpecularAnisotropy);break;case "mapSpecularRepeat":case "mapSpecularOffset":case "mapSpecularWrap":case "mapSpecularAnisotropy":break;case "mapAlpha":l.alphaMap=f(m,d.mapAlphaRepeat,d.mapAlphaOffset,d.mapAlphaWrap,d.mapAlphaAnisotropy);b [...]
+case "flipSided":l.side=THREE.BackSide;break;case "doubleSided":l.side=THREE.DoubleSide;break;case "transparency":console.warn("THREE.Loader: transparency has been renamed to opacity");l.opacity=m;break;case "opacity":case "transparent":case "depthTest":case "depthWrite":case "transparent":case "visible":case "wireframe":l[k]=m;break;case "vertexColors":!0===m&&(l.vertexColors=THREE.VertexColors);"face"===m&&(l.vertexColors=THREE.FaceColors);break;default:console.error("Loader.createMate [...]
+k,m)}}"MeshPhongMaterial"!==l.type&&delete l.specular;1>l.opacity&&(l.transparent=!0);c.setTextures(h);return c.parse(l)}}()};THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=this.handlers,c=0,d=b.length;c<d;c+=2){var e=b[c+1];if(b[c].test(a))return e}return null}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
+THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,g=THREE.Cache.get(a);if(void 0!==g)return b&&setTimeout(function(){b(g)},0),g;var f=new XMLHttpRequest;f.open("GET",a,!0);f.addEventListener("load",function(c){c=c.target.response;THREE.Cache.add(a,c);b&&b(c);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);f.addEventListener("error",function(b){d&&d(b);e.manager.itemError(a)},!1);void 0!==this.crossOrigin&&(f [...]
+this.crossOrigin);void 0!==this.responseType&&(f.responseType=this.responseType);void 0!==this.withCredentials&&(f.withCredentials=this.withCredentials);f.send(null);e.manager.itemStart(a);return f},setResponseType:function(a){this.responseType=a},setCrossOrigin:function(a){this.crossOrigin=a},setWithCredentials:function(a){this.withCredentials=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
+THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,g=THREE.Cache.get(a);if(void 0!==g)return e.manager.itemStart(a),b?setTimeout(function(){b(g);e.manager.itemEnd(a)},0):e.manager.itemEnd(a),g;var f=document.createElement("img");f.addEventListener("load",function(c){THREE.Cache.add(a,this);b&&b(this);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);f.addEventListener("error",function(b){d&&d(b);e.manager.i [...]
+!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);e.manager.itemStart(a);f.src=a;return f},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.JSONLoader=function(a){"boolean"===typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."),a=void 0);this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this.withCredentials=!1};
+THREE.JSONLoader.prototype={constructor:THREE.JSONLoader,get statusDomElement(){void 0===this._statusDomElement&&(this._statusDomElement=document.createElement("div"));console.warn("THREE.JSONLoader: .statusDomElement has been removed.");return this._statusDomElement},load:function(a,b,c,d){var e=this,g=this.texturePath&&"string"===typeof this.texturePath?this.texturePath:THREE.Loader.prototype.extractUrlBase(a);c=new THREE.XHRLoader(this.manager);c.setCrossOrigin(this.crossOrigin);c.set [...]
+c.load(a,function(c){c=JSON.parse(c);var d=c.metadata;if(void 0!==d){if("object"===d.type){console.error("THREE.JSONLoader: "+a+" should be loaded with THREE.ObjectLoader instead.");return}if("scene"===d.type){console.error("THREE.JSONLoader: "+a+" should be loaded with THREE.SceneLoader instead.");return}}c=e.parse(c,g);b(c.geometry,c.materials)})},setCrossOrigin:function(a){this.crossOrigin=a},setTexturePath:function(a){this.texturePath=a},parse:function(a,b){var c=new THREE.Geometry,d [...]
+a.scale?1/a.scale:1;(function(b){var d,f,h,l,k,m,p,n,q,s,t,v,u,w=a.faces;m=a.vertices;var D=a.normals,x=a.colors,B=0;if(void 0!==a.uvs){for(d=0;d<a.uvs.length;d++)a.uvs[d].length&&B++;for(d=0;d<B;d++)c.faceVertexUvs[d]=[]}l=0;for(k=m.length;l<k;)d=new THREE.Vector3,d.x=m[l++]*b,d.y=m[l++]*b,d.z=m[l++]*b,c.vertices.push(d);l=0;for(k=w.length;l<k;)if(b=w[l++],q=b&1,h=b&2,d=b&8,p=b&16,s=b&32,m=b&64,b&=128,q){q=new THREE.Face3;q.a=w[l];q.b=w[l+1];q.c=w[l+3];t=new THREE.Face3;t.a=w[l+1];t.b=w [...]
+w[l+3];l+=4;h&&(h=w[l++],q.materialIndex=h,t.materialIndex=h);h=c.faces.length;if(d)for(d=0;d<B;d++)for(v=a.uvs[d],c.faceVertexUvs[d][h]=[],c.faceVertexUvs[d][h+1]=[],f=0;4>f;f++)n=w[l++],u=v[2*n],n=v[2*n+1],u=new THREE.Vector2(u,n),2!==f&&c.faceVertexUvs[d][h].push(u),0!==f&&c.faceVertexUvs[d][h+1].push(u);p&&(p=3*w[l++],q.normal.set(D[p++],D[p++],D[p]),t.normal.copy(q.normal));if(s)for(d=0;4>d;d++)p=3*w[l++],s=new THREE.Vector3(D[p++],D[p++],D[p]),2!==d&&q.vertexNormals.push(s),0!==d&& [...]
+m&&(m=w[l++],m=x[m],q.color.setHex(m),t.color.setHex(m));if(b)for(d=0;4>d;d++)m=w[l++],m=x[m],2!==d&&q.vertexColors.push(new THREE.Color(m)),0!==d&&t.vertexColors.push(new THREE.Color(m));c.faces.push(q);c.faces.push(t)}else{q=new THREE.Face3;q.a=w[l++];q.b=w[l++];q.c=w[l++];h&&(h=w[l++],q.materialIndex=h);h=c.faces.length;if(d)for(d=0;d<B;d++)for(v=a.uvs[d],c.faceVertexUvs[d][h]=[],f=0;3>f;f++)n=w[l++],u=v[2*n],n=v[2*n+1],u=new THREE.Vector2(u,n),c.faceVertexUvs[d][h].push(u);p&&(p=3*w[ [...]
+D[p++],D[p]));if(s)for(d=0;3>d;d++)p=3*w[l++],s=new THREE.Vector3(D[p++],D[p++],D[p]),q.vertexNormals.push(s);m&&(m=w[l++],q.color.setHex(x[m]));if(b)for(d=0;3>d;d++)m=w[l++],q.vertexColors.push(new THREE.Color(x[m]));c.faces.push(q)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,f=a.skinWeights.length;d<f;d+=b)c.skinWeights.push(new THREE.Vector4(a.skinWeights[d],1<b?a.skinWeights[d+1]:0,2<b?a.skinWeights[d+2]:0,3<b?a.skinWeig [...]
+0));if(a.skinIndices)for(d=0,f=a.skinIndices.length;d<f;d+=b)c.skinIndices.push(new THREE.Vector4(a.skinIndices[d],1<b?a.skinIndices[d+1]:0,2<b?a.skinIndices[d+2]:0,3<b?a.skinIndices[d+3]:0));c.bones=a.bones;c.bones&&0<c.bones.length&&(c.skinWeights.length!==c.skinIndices.length||c.skinIndices.length!==c.vertices.length)&&console.warn("When skinning, number of vertices ("+c.vertices.length+"), skinIndices ("+c.skinIndices.length+"), and skinWeights ("+c.skinWeights.length+") should match [...]
+a.morphTargets)for(var d=0,f=a.morphTargets.length;d<f;d++){c.morphTargets[d]={};c.morphTargets[d].name=a.morphTargets[d].name;c.morphTargets[d].vertices=[];for(var h=c.morphTargets[d].vertices,l=a.morphTargets[d].vertices,k=0,m=l.length;k<m;k+=3){var p=new THREE.Vector3;p.x=l[k]*b;p.y=l[k+1]*b;p.z=l[k+2]*b;h.push(p)}}if(void 0!==a.morphColors&&0<a.morphColors.length)for(console.warn('THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.'),b=c.faces,h=a.morphCol [...]
+d=0,f=b.length;d<f;d++)b[d].color.fromArray(h,3*d)})(d);(function(){var b=[],d=[];void 0!==a.animation&&d.push(a.animation);void 0!==a.animations&&(a.animations.length?d=d.concat(a.animations):d.push(a.animations));for(var f=0;f<d.length;f++){var h=THREE.AnimationClip.parseAnimation(d[f],c.bones);h&&b.push(h)}c.morphTargets&&(d=THREE.AnimationClip.CreateClipsFromMorphTargetSequences(c.morphTargets,10),b=b.concat(d));0<b.length&&(c.animations=b)})();c.computeFaceNormals();c.computeBoundin [...]
+if(void 0===a.materials||0===a.materials.length)return{geometry:c};d=THREE.Loader.prototype.initMaterials(a.materials,b,this.crossOrigin);return{geometry:c,materials:d}}};
+THREE.LoadingManager=function(a,b,c){var d=this,e=!1,g=0,f=0;this.onStart=void 0;this.onLoad=a;this.onProgress=b;this.onError=c;this.itemStart=function(a){f++;if(!1===e&&void 0!==d.onStart)d.onStart(a,g,f);e=!0};this.itemEnd=function(a){g++;if(void 0!==d.onProgress)d.onProgress(a,g,f);if(g===f&&(e=!1,void 0!==d.onLoad))d.onLoad()};this.itemError=function(a){if(void 0!==d.onError)d.onError(a)}};THREE.DefaultLoadingManager=new THREE.LoadingManager;
+THREE.BufferGeometryLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
+THREE.BufferGeometryLoader.prototype={constructor:THREE.BufferGeometryLoader,load:function(a,b,c,d){var e=this,g=new THREE.XHRLoader(e.manager);g.setCrossOrigin(this.crossOrigin);g.load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new THREE.BufferGeometry,c=a.data.index;void 0!==c&&(c=new self[c.type](c.array),b.setIndex(new THREE.BufferAttribute(c,1)));var d=a.data.attributes,e;for(e in d){var g=d[e],c=new self[g.t [...]
+b.addAttribute(e,new THREE.BufferAttribute(c,g.itemSize))}e=a.data.groups||a.data.drawcalls||a.data.offsets;if(void 0!==e)for(c=0,d=e.length;c!==d;++c)g=e[c],b.addGroup(g.start,g.count);a=a.data.boundingSphere;void 0!==a&&(e=new THREE.Vector3,void 0!==a.center&&e.fromArray(a.center),b.boundingSphere=new THREE.Sphere(e,a.radius));return b}};THREE.MaterialLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this.textures={}};
+THREE.MaterialLoader.prototype={constructor:THREE.MaterialLoader,load:function(a,b,c,d){var e=this,g=new THREE.XHRLoader(e.manager);g.setCrossOrigin(this.crossOrigin);g.load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},setCrossOrigin:function(a){this.crossOrigin=a},setTextures:function(a){this.textures=a},getTexture:function(a){var b=this.textures;void 0===b[a]&&console.warn("THREE.MaterialLoader: Undefined texture",a);return b[a]},parse:function(a){var b=new THREE[a.type];b.uuid=a.uui [...]
+a.name&&(b.name=a.name);void 0!==a.color&&b.color.setHex(a.color);void 0!==a.emissive&&b.emissive.setHex(a.emissive);void 0!==a.specular&&b.specular.setHex(a.specular);void 0!==a.shininess&&(b.shininess=a.shininess);void 0!==a.uniforms&&(b.uniforms=a.uniforms);void 0!==a.vertexShader&&(b.vertexShader=a.vertexShader);void 0!==a.fragmentShader&&(b.fragmentShader=a.fragmentShader);void 0!==a.vertexColors&&(b.vertexColors=a.vertexColors);void 0!==a.shading&&(b.shading=a.shading);void 0!==a.b [...]
+(b.blending=a.blending);void 0!==a.side&&(b.side=a.side);void 0!==a.opacity&&(b.opacity=a.opacity);void 0!==a.transparent&&(b.transparent=a.transparent);void 0!==a.alphaTest&&(b.alphaTest=a.alphaTest);void 0!==a.depthTest&&(b.depthTest=a.depthTest);void 0!==a.depthWrite&&(b.depthWrite=a.depthWrite);void 0!==a.wireframe&&(b.wireframe=a.wireframe);void 0!==a.wireframeLinewidth&&(b.wireframeLinewidth=a.wireframeLinewidth);void 0!==a.size&&(b.size=a.size);void 0!==a.sizeAttenuation&&(b.sizeA [...]
+a.sizeAttenuation);void 0!==a.map&&(b.map=this.getTexture(a.map));void 0!==a.alphaMap&&(b.alphaMap=this.getTexture(a.alphaMap),b.transparent=!0);void 0!==a.bumpMap&&(b.bumpMap=this.getTexture(a.bumpMap));void 0!==a.bumpScale&&(b.bumpScale=a.bumpScale);void 0!==a.normalMap&&(b.normalMap=this.getTexture(a.normalMap));a.normalScale&&(b.normalScale=new THREE.Vector2(a.normalScale,a.normalScale));void 0!==a.displacementMap&&(b.displacementMap=this.getTexture(a.displacementMap));void 0!==a.dis [...]
+(b.displacementScale=a.displacementScale);void 0!==a.displacementBias&&(b.displacementBias=a.displacementBias);void 0!==a.specularMap&&(b.specularMap=this.getTexture(a.specularMap));void 0!==a.envMap&&(b.envMap=this.getTexture(a.envMap),b.combine=THREE.MultiplyOperation);a.reflectivity&&(b.reflectivity=a.reflectivity);void 0!==a.lightMap&&(b.lightMap=this.getTexture(a.lightMap));void 0!==a.lightMapIntensity&&(b.lightMapIntensity=a.lightMapIntensity);void 0!==a.aoMap&&(b.aoMap=this.getTex [...]
+void 0!==a.aoMapIntensity&&(b.aoMapIntensity=a.aoMapIntensity);if(void 0!==a.materials)for(var c=0,d=a.materials.length;c<d;c++)b.materials.push(this.parse(a.materials[c]));return b}};THREE.ObjectLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this.texturePath=""};
+THREE.ObjectLoader.prototype={constructor:THREE.ObjectLoader,load:function(a,b,c,d){""===this.texturePath&&(this.texturePath=a.substring(0,a.lastIndexOf("/")+1));var e=this,g=new THREE.XHRLoader(e.manager);g.setCrossOrigin(this.crossOrigin);g.load(a,function(a){e.parse(JSON.parse(a),b)},c,d)},setTexturePath:function(a){this.texturePath=a},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a,b){var c=this.parseGeometries(a.geometries),d=this.parseImages(a.images,function(){void [...]
+d=this.parseTextures(a.textures,d),d=this.parseMaterials(a.materials,d),e=this.parseObject(a.object,c,d);a.animations&&(e.animations=this.parseAnimations(a.animations));void 0!==a.images&&0!==a.images.length||void 0===b||b(e);return e},parseGeometries:function(a){var b={};if(void 0!==a)for(var c=new THREE.JSONLoader,d=new THREE.BufferGeometryLoader,e=0,g=a.length;e<g;e++){var f,h=a[e];switch(h.type){case "PlaneGeometry":case "PlaneBufferGeometry":f=new THREE[h.type](h.width,h.height,h.wi [...]
+h.heightSegments);break;case "BoxGeometry":case "CubeGeometry":f=new THREE.BoxGeometry(h.width,h.height,h.depth,h.widthSegments,h.heightSegments,h.depthSegments);break;case "CircleBufferGeometry":f=new THREE.CircleBufferGeometry(h.radius,h.segments,h.thetaStart,h.thetaLength);break;case "CircleGeometry":f=new THREE.CircleGeometry(h.radius,h.segments,h.thetaStart,h.thetaLength);break;case "CylinderGeometry":f=new THREE.CylinderGeometry(h.radiusTop,h.radiusBottom,h.height,h.radialSegments, [...]
+h.openEnded,h.thetaStart,h.thetaLength);break;case "SphereGeometry":f=new THREE.SphereGeometry(h.radius,h.widthSegments,h.heightSegments,h.phiStart,h.phiLength,h.thetaStart,h.thetaLength);break;case "SphereBufferGeometry":f=new THREE.SphereBufferGeometry(h.radius,h.widthSegments,h.heightSegments,h.phiStart,h.phiLength,h.thetaStart,h.thetaLength);break;case "DodecahedronGeometry":f=new THREE.DodecahedronGeometry(h.radius,h.detail);break;case "IcosahedronGeometry":f=new THREE.IcosahedronGe [...]
+h.detail);break;case "OctahedronGeometry":f=new THREE.OctahedronGeometry(h.radius,h.detail);break;case "TetrahedronGeometry":f=new THREE.TetrahedronGeometry(h.radius,h.detail);break;case "RingGeometry":f=new THREE.RingGeometry(h.innerRadius,h.outerRadius,h.thetaSegments,h.phiSegments,h.thetaStart,h.thetaLength);break;case "TorusGeometry":f=new THREE.TorusGeometry(h.radius,h.tube,h.radialSegments,h.tubularSegments,h.arc);break;case "TorusKnotGeometry":f=new THREE.TorusKnotGeometry(h.radiu [...]
+h.radialSegments,h.tubularSegments,h.p,h.q,h.heightScale);break;case "BufferGeometry":f=d.parse(h);break;case "Geometry":f=c.parse(h.data,this.texturePath).geometry;break;default:console.warn('THREE.ObjectLoader: Unsupported geometry type "'+h.type+'"');continue}f.uuid=h.uuid;void 0!==h.name&&(f.name=h.name);b[h.uuid]=f}return b},parseMaterials:function(a,b){var c={};if(void 0!==a){var d=new THREE.MaterialLoader;d.setTextures(b);for(var e=0,g=a.length;e<g;e++){var f=d.parse(a[e]);c[f.uui [...]
+parseAnimations:function(a){for(var b=[],c=0;c<a.length;c++){var d=THREE.AnimationClip.parse(a[c]);b.push(d)}return b},parseImages:function(a,b){function c(a){d.manager.itemStart(a);return f.load(a,function(){d.manager.itemEnd(a)})}var d=this,e={};if(void 0!==a&&0<a.length){var g=new THREE.LoadingManager(b),f=new THREE.ImageLoader(g);f.setCrossOrigin(this.crossOrigin);for(var g=0,h=a.length;g<h;g++){var l=a[g],k=/^(\/\/)|([a-z]+:(\/\/)?)/i.test(l.url)?l.url:d.texturePath+l.url;e[l.uuid]= [...]
+parseTextures:function(a,b){function c(a){if("number"===typeof a)return a;console.warn("THREE.ObjectLoader.parseTexture: Constant should be in numeric form.",a);return THREE[a]}var d={};if(void 0!==a)for(var e=0,g=a.length;e<g;e++){var f=a[e];void 0===f.image&&console.warn('THREE.ObjectLoader: No "image" specified for',f.uuid);void 0===b[f.image]&&console.warn("THREE.ObjectLoader: Undefined image",f.image);var h=new THREE.Texture(b[f.image]);h.needsUpdate=!0;h.uuid=f.uuid;void 0!==f.name [...]
+f.name);void 0!==f.mapping&&(h.mapping=c(f.mapping));void 0!==f.offset&&(h.offset=new THREE.Vector2(f.offset[0],f.offset[1]));void 0!==f.repeat&&(h.repeat=new THREE.Vector2(f.repeat[0],f.repeat[1]));void 0!==f.minFilter&&(h.minFilter=c(f.minFilter));void 0!==f.magFilter&&(h.magFilter=c(f.magFilter));void 0!==f.anisotropy&&(h.anisotropy=f.anisotropy);Array.isArray(f.wrap)&&(h.wrapS=c(f.wrap[0]),h.wrapT=c(f.wrap[1]));d[f.uuid]=h}return d},parseObject:function(){var a=new THREE.Matrix4;retu [...]
+c,d){function e(a){void 0===c[a]&&console.warn("THREE.ObjectLoader: Undefined geometry",a);return c[a]}function g(a){if(void 0!==a)return void 0===d[a]&&console.warn("THREE.ObjectLoader: Undefined material",a),d[a]}var f;switch(b.type){case "Scene":f=new THREE.Scene;break;case "PerspectiveCamera":f=new THREE.PerspectiveCamera(b.fov,b.aspect,b.near,b.far);break;case "OrthographicCamera":f=new THREE.OrthographicCamera(b.left,b.right,b.top,b.bottom,b.near,b.far);break;case "AmbientLight":f= [...]
+break;case "DirectionalLight":f=new THREE.DirectionalLight(b.color,b.intensity);break;case "PointLight":f=new THREE.PointLight(b.color,b.intensity,b.distance,b.decay);break;case "SpotLight":f=new THREE.SpotLight(b.color,b.intensity,b.distance,b.angle,b.exponent,b.decay);break;case "HemisphereLight":f=new THREE.HemisphereLight(b.color,b.groundColor,b.intensity);break;case "Mesh":f=new THREE.Mesh(e(b.geometry),g(b.material));break;case "LOD":f=new THREE.LOD;break;case "Line":f=new THREE.Li [...]
+g(b.material),b.mode);break;case "PointCloud":case "Points":f=new THREE.Points(e(b.geometry),g(b.material));break;case "Sprite":f=new THREE.Sprite(g(b.material));break;case "Group":f=new THREE.Group;break;default:f=new THREE.Object3D}f.uuid=b.uuid;void 0!==b.name&&(f.name=b.name);void 0!==b.matrix?(a.fromArray(b.matrix),a.decompose(f.position,f.quaternion,f.scale)):(void 0!==b.position&&f.position.fromArray(b.position),void 0!==b.rotation&&f.rotation.fromArray(b.rotation),void 0!==b.scal [...]
+void 0!==b.castShadow&&(f.castShadow=b.castShadow);void 0!==b.receiveShadow&&(f.receiveShadow=b.receiveShadow);void 0!==b.visible&&(f.visible=b.visible);void 0!==b.userData&&(f.userData=b.userData);if(void 0!==b.children)for(var h in b.children)f.add(this.parseObject(b.children[h],c,d));if("LOD"===b.type){b=b.levels;for(var l=0;l<b.length;l++){var k=b[l];h=f.getObjectByProperty("uuid",k.object);void 0!==h&&f.addLevel(h,k.distance)}}return f}}()};
+THREE.TextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};THREE.TextureLoader.prototype={constructor:THREE.TextureLoader,load:function(a,b,c,d){var e=new THREE.Texture,g=new THREE.ImageLoader(this.manager);g.setCrossOrigin(this.crossOrigin);g.load(a,function(a){e.image=a;e.needsUpdate=!0;void 0!==b&&b(e)},c,d);return e},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.CubeTextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
+THREE.CubeTextureLoader.prototype={constructor:THREE.CubeTextureLoader,load:function(a,b,c,d){function e(c){f.load(a[c],function(a){g.images[c]=a;h++;6===h&&(g.needsUpdate=!0,b&&b(g))},void 0,d)}var g=new THREE.CubeTexture([]),f=new THREE.ImageLoader;f.setCrossOrigin(this.crossOrigin);var h=0;for(c=0;c<a.length;++c)e(c);return g},setCrossOrigin:function(a){this.crossOrigin=a}};
+THREE.DataTextureLoader=THREE.BinaryTextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this._parser=null};
+THREE.BinaryTextureLoader.prototype={constructor:THREE.BinaryTextureLoader,load:function(a,b,c,d){var e=this,g=new THREE.DataTexture,f=new THREE.XHRLoader(this.manager);f.setCrossOrigin(this.crossOrigin);f.setResponseType("arraybuffer");f.load(a,function(a){if(a=e._parser(a))void 0!==a.image?g.image=a.image:void 0!==a.data&&(g.image.width=a.width,g.image.height=a.height,g.image.data=a.data),g.wrapS=void 0!==a.wrapS?a.wrapS:THREE.ClampToEdgeWrapping,g.wrapT=void 0!==a.wrapT?a.wrapT:THREE. [...]
+g.magFilter=void 0!==a.magFilter?a.magFilter:THREE.LinearFilter,g.minFilter=void 0!==a.minFilter?a.minFilter:THREE.LinearMipMapLinearFilter,g.anisotropy=void 0!==a.anisotropy?a.anisotropy:1,void 0!==a.format&&(g.format=a.format),void 0!==a.type&&(g.type=a.type),void 0!==a.mipmaps&&(g.mipmaps=a.mipmaps),1===a.mipmapCount&&(g.minFilter=THREE.LinearFilter),g.needsUpdate=!0,b&&b(g,a)},c,d);return g},setCrossOrigin:function(a){this.crossOrigin=a}};
+THREE.CompressedTextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this._parser=null};
+THREE.CompressedTextureLoader.prototype={constructor:THREE.CompressedTextureLoader,load:function(a,b,c,d){var e=this,g=[],f=new THREE.CompressedTexture;f.image=g;var h=new THREE.XHRLoader(this.manager);h.setCrossOrigin(this.crossOrigin);h.setResponseType("arraybuffer");if(Array.isArray(a))for(var l=0,k=function(k){h.load(a[k],function(a){a=e._parser(a,!0);g[k]={width:a.width,height:a.height,format:a.format,mipmaps:a.mipmaps};l+=1;6===l&&(1===a.mipmapCount&&(f.minFilter=THREE.LinearFilter [...]
+a.format,f.needsUpdate=!0,b&&b(f))},c,d)},m=0,p=a.length;m<p;++m)k(m);else h.load(a,function(a){a=e._parser(a,!0);if(a.isCubemap)for(var c=a.mipmaps.length/a.mipmapCount,d=0;d<c;d++){g[d]={mipmaps:[]};for(var h=0;h<a.mipmapCount;h++)g[d].mipmaps.push(a.mipmaps[d*a.mipmapCount+h]),g[d].format=a.format,g[d].width=a.width,g[d].height=a.height}else f.image.width=a.width,f.image.height=a.height,f.mipmaps=a.mipmaps;1===a.mipmapCount&&(f.minFilter=THREE.LinearFilter);f.format=a.format;f.needsUp [...]
+b(f)},c,d);return f},setCrossOrigin:function(a){this.crossOrigin=a}};
+THREE.Material=function(){Object.defineProperty(this,"id",{value:THREE.MaterialIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Material";this.side=THREE.FrontSide;this.opacity=1;this.transparent=!1;this.blending=THREE.NormalBlending;this.blendSrc=THREE.SrcAlphaFactor;this.blendDst=THREE.OneMinusSrcAlphaFactor;this.blendEquation=THREE.AddEquation;this.blendEquationAlpha=this.blendDstAlpha=this.blendSrcAlpha=null;this.depthFunc=THREE.LessEqualDepth;this.colorWrite=t [...]
+this.depthTest=!0;this.precision=null;this.polygonOffset=!1;this.overdraw=this.alphaTest=this.polygonOffsetUnits=this.polygonOffsetFactor=0;this._needsUpdate=this.visible=!0};
+THREE.Material.prototype={constructor:THREE.Material,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+b+"' parameter is undefined.");else{var d=this[b];void 0===d?console.warn("THREE."+this.type+": '"+b+"' is not a property of this material."):d instanceof THREE.Color?d.set(c):d instanceof THREE.Vector3&&c instanceof THREE. [...]
+this[b]="overdraw"===b?Number(c):c}}},toJSON:function(a){var b={metadata:{version:4.4,type:"Material",generator:"Material.toJSON"}};b.uuid=this.uuid;b.type=this.type;""!==this.name&&(b.name=this.name);this.color instanceof THREE.Color&&(b.color=this.color.getHex());this.emissive instanceof THREE.Color&&(b.emissive=this.emissive.getHex());this.specular instanceof THREE.Color&&(b.specular=this.specular.getHex());void 0!==this.shininess&&(b.shininess=this.shininess);this.map instanceof THRE [...]
+(b.map=this.map.toJSON(a).uuid);this.alphaMap instanceof THREE.Texture&&(b.alphaMap=this.alphaMap.toJSON(a).uuid);this.lightMap instanceof THREE.Texture&&(b.lightMap=this.lightMap.toJSON(a).uuid);this.bumpMap instanceof THREE.Texture&&(b.bumpMap=this.bumpMap.toJSON(a).uuid,b.bumpScale=this.bumpScale);this.normalMap instanceof THREE.Texture&&(b.normalMap=this.normalMap.toJSON(a).uuid,b.normalScale=this.normalScale);this.displacementMap instanceof THREE.Texture&&(b.displacementMap=this.dis [...]
+b.displacementScale=this.displacementScale,b.displacementBias=this.displacementBias);this.specularMap instanceof THREE.Texture&&(b.specularMap=this.specularMap.toJSON(a).uuid);this.envMap instanceof THREE.Texture&&(b.envMap=this.envMap.toJSON(a).uuid,b.reflectivity=this.reflectivity);void 0!==this.size&&(b.size=this.size);void 0!==this.sizeAttenuation&&(b.sizeAttenuation=this.sizeAttenuation);void 0!==this.vertexColors&&this.vertexColors!==THREE.NoColors&&(b.vertexColors=this.vertexColor [...]
+this.shading&&this.shading!==THREE.SmoothShading&&(b.shading=this.shading);void 0!==this.blending&&this.blending!==THREE.NormalBlending&&(b.blending=this.blending);void 0!==this.side&&this.side!==THREE.FrontSide&&(b.side=this.side);1>this.opacity&&(b.opacity=this.opacity);!0===this.transparent&&(b.transparent=this.transparent);0<this.alphaTest&&(b.alphaTest=this.alphaTest);!0===this.wireframe&&(b.wireframe=this.wireframe);1<this.wireframeLinewidth&&(b.wireframeLinewidth=this.wireframeLin [...]
+clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.side=a.side;this.opacity=a.opacity;this.transparent=a.transparent;this.blending=a.blending;this.blendSrc=a.blendSrc;this.blendDst=a.blendDst;this.blendEquation=a.blendEquation;this.blendSrcAlpha=a.blendSrcAlpha;this.blendDstAlpha=a.blendDstAlpha;this.blendEquationAlpha=a.blendEquationAlpha;this.depthFunc=a.depthFunc;this.depthTest=a.depthTest;this.depthWrite=a.depthWrite;this.precision=a.prec [...]
+a.polygonOffset;this.polygonOffsetFactor=a.polygonOffsetFactor;this.polygonOffsetUnits=a.polygonOffsetUnits;this.alphaTest=a.alphaTest;this.overdraw=a.overdraw;this.visible=a.visible;return this},update:function(){this.dispatchEvent({type:"update"})},dispose:function(){this.dispatchEvent({type:"dispose"})},get wrapAround(){console.warn("THREE."+this.type+": .wrapAround has been removed.")},set wrapAround(a){console.warn("THREE."+this.type+": .wrapAround has been removed.")},get wrapRGB() [...]
+this.type+": .wrapRGB has been removed.");return new THREE.Color}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0;THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.type="LineBasicMaterial";this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype);
+THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial;THREE.LineBasicMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.linewidth=a.linewidth;this.linecap=a.linecap;this.linejoin=a.linejoin;this.vertexColors=a.vertexColors;this.fog=a.fog;return this};
+THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.type="LineDashedMaterial";this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype);THREE.LineDashedMaterial.prototype.constructor=THREE.LineDashedMaterial;
+THREE.LineDashedMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.linewidth=a.linewidth;this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize=a.gapSize;this.vertexColors=a.vertexColors;this.fog=a.fog;return this};
+THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.type="MeshBasicMaterial";this.color=new THREE.Color(16777215);this.aoMap=this.map=null;this.aoMapIntensity=1;this.envMap=this.alphaMap=this.specularMap=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphT [...]
+!1;this.setValues(a)};THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshBasicMaterial.prototype.constructor=THREE.MeshBasicMaterial;
+THREE.MeshBasicMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.fog=a.fog;this.shading=a.shading;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLineca [...]
+this.wireframeLinejoin=a.wireframeLinejoin;this.vertexColors=a.vertexColors;this.skinning=a.skinning;this.morphTargets=a.morphTargets;return this};
+THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.type="MeshLambertMaterial";this.color=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.envMap=this.alphaMap=this.specularMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skin [...]
+THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshLambertMaterial.prototype.constructor=THREE.MeshLambertMaterial;
+THREE.MeshLambertMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.emissive.copy(a.emissive);this.map=a.map;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.fog=a.fog;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a. [...]
+this.vertexColors=a.vertexColors;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};
+THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.type="MeshPhongMaterial";this.color=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.metal=!1;this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.bumpMap=this.emissiveMap=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.displacementMap=null;this.displacementScale=1;this. [...]
+0;this.envMap=this.alphaMap=this.specularMap=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshPhongMaterial.prototype.const [...]
+THREE.MeshPhongMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.emissive.copy(a.emissive);this.specular.copy(a.specular);this.shininess=a.shininess;this.metal=a.metal;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissiveMap=a.emissiveMap;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.c [...]
+this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.fog=a.fog;this.shading=a.shading;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;thi [...]
+a.vertexColors;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.type="MeshDepthMaterial";this.wireframe=this.morphTargets=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.constructor=THREE.MeshDepthMaterial;
+THREE.MeshDepthMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshN [...]
+THREE.MeshNormalMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};THREE.MultiMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MultiMaterial";this.materials=a instanceof Array?a:[];this.visible=!0};
+THREE.MultiMaterial.prototype={constructor:THREE.MultiMaterial,toJSON:function(){for(var a={metadata:{version:4.2,type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type,materials:[]},b=0,c=this.materials.length;b<c;b++)a.materials.push(this.materials[b].toJSON());a.visible=this.visible;return a},clone:function(){for(var a=new this.constructor,b=0;b<this.materials.length;b++)a.materials.push(this.materials[b].clone());a.visible=this.visible;return a}};THREE.MeshFaceMa [...]
+THREE.PointsMaterial=function(a){THREE.Material.call(this);this.type="PointsMaterial";this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=!0;this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.PointsMaterial.prototype=Object.create(THREE.Material.prototype);THREE.PointsMaterial.prototype.constructor=THREE.PointsMaterial;
+THREE.PointsMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.size=a.size;this.sizeAttenuation=a.sizeAttenuation;this.vertexColors=a.vertexColors;this.fog=a.fog;return this};THREE.PointCloudMaterial=function(a){console.warn("THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.");return new THREE.PointsMaterial(a)};
+THREE.ParticleBasicMaterial=function(a){console.warn("THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.");return new THREE.PointsMaterial(a)};THREE.ParticleSystemMaterial=function(a){console.warn("THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.");return new THREE.PointsMaterial(a)};
+THREE.ShaderMaterial=function(a){THREE.Material.call(this);this.type="ShaderMaterial";this.defines={};this.uniforms={};this.vertexShader="void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";this.fragmentShader="void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";this.shading=THREE.SmoothShading;this.linewidth=1;this.wireframe=!1;this.wireframeLinewidth=1;this.lights=this.fog=!1;this.vertexColors=THREE.NoColors;this.derivatives=this.m [...]
+this.morphTargets=this.skinning=!1;this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv2:[0,0]};this.index0AttributeName=void 0;void 0!==a&&(void 0!==a.attributes&&console.error("THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead."),this.setValues(a))};THREE.ShaderMaterial.prototype=Object.create(THREE.Material.prototype);THREE.ShaderMaterial.prototype.constructor=THREE.ShaderMaterial;
+THREE.ShaderMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.fragmentShader=a.fragmentShader;this.vertexShader=a.vertexShader;this.uniforms=THREE.UniformsUtils.clone(a.uniforms);this.attributes=a.attributes;this.defines=a.defines;this.shading=a.shading;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.fog=a.fog;this.lights=a.lights;this.vertexColors=a.vertexColors;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this. [...]
+a.morphNormals;this.derivatives=a.derivatives;return this};THREE.ShaderMaterial.prototype.toJSON=function(a){a=THREE.Material.prototype.toJSON.call(this,a);a.uniforms=this.uniforms;a.attributes=this.attributes;a.vertexShader=this.vertexShader;a.fragmentShader=this.fragmentShader;return a};THREE.RawShaderMaterial=function(a){THREE.ShaderMaterial.call(this,a);this.type="RawShaderMaterial"};THREE.RawShaderMaterial.prototype=Object.create(THREE.ShaderMaterial.prototype);
+THREE.RawShaderMaterial.prototype.constructor=THREE.RawShaderMaterial;THREE.SpriteMaterial=function(a){THREE.Material.call(this);this.type="SpriteMaterial";this.color=new THREE.Color(16777215);this.map=null;this.rotation=0;this.fog=!1;this.setValues(a)};THREE.SpriteMaterial.prototype=Object.create(THREE.Material.prototype);THREE.SpriteMaterial.prototype.constructor=THREE.SpriteMaterial;
+THREE.SpriteMaterial.prototype.copy=function(a){THREE.Material.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.rotation=a.rotation;this.fog=a.fog;return this};
+THREE.Texture=function(a,b,c,d,e,g,f,h,l){Object.defineProperty(this,"id",{value:THREE.TextureIdCount++});this.uuid=THREE.Math.generateUUID();this.sourceFile=this.name="";this.image=void 0!==a?a:THREE.Texture.DEFAULT_IMAGE;this.mipmaps=[];this.mapping=void 0!==b?b:THREE.Texture.DEFAULT_MAPPING;this.wrapS=void 0!==c?c:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==d?d:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==e?e:THREE.LinearFilter;this.minFilter=void 0!==g?g:THREE.LinearMipMapLine [...]
+this.anisotropy=void 0!==l?l:1;this.format=void 0!==f?f:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this.version=0;this.onUpdate=null};THREE.Texture.DEFAULT_IMAGE=void 0;THREE.Texture.DEFAULT_MAPPING=THREE.UVMapping;
+THREE.Texture.prototype={constructor:THREE.Texture,set needsUpdate(a){!0===a&&this.version++},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter=a.magFilter;this.minFilter=a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset);this.repeat.copy(a.repeat);this.generateMipmaps=a.generateMipma [...]
+a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;return this},toJSON:function(a){if(void 0!==a.textures[this.uuid])return a.textures[this.uuid];var b={metadata:{version:4.4,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy};if(void 0!==this [...]
+this.image;void 0===c.uuid&&(c.uuid=THREE.Math.generateUUID());if(void 0===a.images[c.uuid]){var d=a.images,e=c.uuid,g=c.uuid,f;void 0!==c.toDataURL?f=c:(f=document.createElement("canvas"),f.width=c.width,f.height=c.height,f.getContext("2d").drawImage(c,0,0,c.width,c.height));f=2048<f.width||2048<f.height?f.toDataURL("image/jpeg",.6):f.toDataURL("image/png");d[e]={uuid:g,url:f}}b.image=c.uuid}return a.textures[this.uuid]=b},dispose:function(){this.dispatchEvent({type:"dispose"})},transfo [...]
+THREE.UVMapping){a.multiply(this.repeat);a.add(this.offset);if(0>a.x||1<a.x)switch(this.wrapS){case THREE.RepeatWrapping:a.x-=Math.floor(a.x);break;case THREE.ClampToEdgeWrapping:a.x=0>a.x?0:1;break;case THREE.MirroredRepeatWrapping:1===Math.abs(Math.floor(a.x)%2)?a.x=Math.ceil(a.x)-a.x:a.x-=Math.floor(a.x)}if(0>a.y||1<a.y)switch(this.wrapT){case THREE.RepeatWrapping:a.y-=Math.floor(a.y);break;case THREE.ClampToEdgeWrapping:a.y=0>a.y?0:1;break;case THREE.MirroredRepeatWrapping:1===Math.a [...]
+2)?a.y=Math.ceil(a.y)-a.y:a.y-=Math.floor(a.y)}this.flipY&&(a.y=1-a.y)}}};THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype);THREE.TextureIdCount=0;THREE.CanvasTexture=function(a,b,c,d,e,g,f,h,l){THREE.Texture.call(this,a,b,c,d,e,g,f,h,l);this.needsUpdate=!0};THREE.CanvasTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CanvasTexture.prototype.constructor=THREE.CanvasTexture;
+THREE.CubeTexture=function(a,b,c,d,e,g,f,h,l){b=void 0!==b?b:THREE.CubeReflectionMapping;THREE.Texture.call(this,a,b,c,d,e,g,f,h,l);this.images=a;this.flipY=!1};THREE.CubeTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CubeTexture.prototype.constructor=THREE.CubeTexture;THREE.CubeTexture.prototype.copy=function(a){THREE.Texture.prototype.copy.call(this,a);this.images=a.images;return this};
+THREE.CompressedTexture=function(a,b,c,d,e,g,f,h,l,k,m){THREE.Texture.call(this,null,g,f,h,l,k,d,e,m);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CompressedTexture.prototype.constructor=THREE.CompressedTexture;
+THREE.DataTexture=function(a,b,c,d,e,g,f,h,l,k,m){THREE.Texture.call(this,null,g,f,h,l,k,d,e,m);this.image={data:a,width:b,height:c};this.magFilter=void 0!==l?l:THREE.NearestFilter;this.minFilter=void 0!==k?k:THREE.NearestFilter;this.generateMipmaps=this.flipY=!1};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.constructor=THREE.DataTexture;
+THREE.VideoTexture=function(a,b,c,d,e,g,f,h,l){function k(){requestAnimationFrame(k);a.readyState===a.HAVE_ENOUGH_DATA&&(m.needsUpdate=!0)}THREE.Texture.call(this,a,b,c,d,e,g,f,h,l);this.generateMipmaps=!1;var m=this;k()};THREE.VideoTexture.prototype=Object.create(THREE.Texture.prototype);THREE.VideoTexture.prototype.constructor=THREE.VideoTexture;THREE.Group=function(){THREE.Object3D.call(this);this.type="Group"};THREE.Group.prototype=Object.create(THREE.Object3D.prototype);
+THREE.Group.prototype.constructor=THREE.Group;THREE.Points=function(a,b){THREE.Object3D.call(this);this.type="Points";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.PointsMaterial({color:16777215*Math.random()})};THREE.Points.prototype=Object.create(THREE.Object3D.prototype);THREE.Points.prototype.constructor=THREE.Points;
+THREE.Points.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray;return function(c,d){function e(a,e){var f=b.distanceSqToPoint(a);if(f<l){var h=b.closestPointToPoint(a);h.applyMatrix4(g.matrixWorld);var k=c.ray.origin.distanceTo(h);k<c.near||k>c.far||d.push({distance:k,distanceToRay:Math.sqrt(f),point:h.clone(),index:e,face:null,object:g})}}var g=this,f=g.geometry,h=c.params.Points.threshold;a.getInverse(this.matrixWorld);b.copy(c.ray).applyMatrix4(a);if(null===f.boundi [...]
+b.isIntersectionBox(f.boundingBox)){var h=h/((this.scale.x+this.scale.y+this.scale.z)/3),l=h*h,h=new THREE.Vector3;if(f instanceof THREE.BufferGeometry){var k=f.index,f=f.attributes.position.array;if(null!==k)for(var m=k.array,k=0,p=m.length;k<p;k++){var n=m[k];h.fromArray(f,3*n);e(h,n)}else for(k=0,m=f.length/3;k<m;k++)h.fromArray(f,3*k),e(h,k)}else for(h=f.vertices,k=0,m=h.length;k<m;k++)e(h[k],k)}}}();THREE.Points.prototype.clone=function(){return(new this.constructor(this.geometry,th [...]
+THREE.PointCloud=function(a,b){console.warn("THREE.PointCloud has been renamed to THREE.Points.");return new THREE.Points(a,b)};THREE.ParticleSystem=function(a,b){console.warn("THREE.ParticleSystem has been renamed to THREE.Points.");return new THREE.Points(a,b)};
+THREE.Line=function(a,b,c){if(1===c)return console.warn("THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead."),new THREE.LineSegments(a,b);THREE.Object3D.call(this);this.type="Line";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()})};THREE.Line.prototype=Object.create(THREE.Object3D.prototype);THREE.Line.prototype.constructor=THREE.Line;
+THREE.Line.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere;return function(d,e){var g=d.linePrecision,g=g*g,f=this.geometry;null===f.boundingSphere&&f.computeBoundingSphere();c.copy(f.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==d.ray.isIntersectionSphere(c)){a.getInverse(this.matrixWorld);b.copy(d.ray).applyMatrix4(a);var h=new THREE.Vector3,l=new THREE.Vector3,k=new THREE.Vector3,m=new THREE.Vector3,p=this instanceof THREE.LineSegment [...]
+THREE.BufferGeometry){var n=f.index,q=f.attributes;if(null!==n)for(var f=n.array,q=q.position.array,n=0,s=f.length-1;n<s;n+=p){var t=f[n+1];h.fromArray(q,3*f[n]);l.fromArray(q,3*t);t=b.distanceSqToSegment(h,l,m,k);t>g||(m.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(m),t<d.near||t>d.far||e.push({distance:t,point:k.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this}))}else for(q=q.position.array,n=0,s=q.length/3-1;n<s;n+=p)h.fromArray(q,3*n),l. [...]
+3*n+3),t=b.distanceSqToSegment(h,l,m,k),t>g||(m.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(m),t<d.near||t>d.far||e.push({distance:t,point:k.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this}))}else if(f instanceof THREE.Geometry)for(h=f.vertices,l=h.length,n=0;n<l-1;n+=p)t=b.distanceSqToSegment(h[n],h[n+1],m,k),t>g||(m.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(m),t<d.near||t>d.far||e.push({distance:t,point:k.clone().applyMatr [...]
+index:n,face:null,faceIndex:null,object:this}))}}}();THREE.Line.prototype.clone=function(){return(new this.constructor(this.geometry,this.material)).copy(this)};THREE.LineStrip=0;THREE.LinePieces=1;THREE.LineSegments=function(a,b){THREE.Line.call(this,a,b);this.type="LineSegments"};THREE.LineSegments.prototype=Object.create(THREE.Line.prototype);THREE.LineSegments.prototype.constructor=THREE.LineSegments;
+THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype);THREE.Mesh.prototype.constructor=THREE.Mesh;
+THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}};
+THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.warn("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};
+THREE.Mesh.prototype.raycast=function(){function a(a,b,c,d,e,f,g){THREE.Triangle.barycoordFromPoint(a,b,c,d,t);e.multiplyScalar(t.x);f.multiplyScalar(t.y);g.multiplyScalar(t.z);e.add(f).add(g);return e.clone()}function b(a,b,c,d,e,f,g){var h=a.material;if(null===(h.side===THREE.BackSide?c.intersectTriangle(f,e,d,!0,g):c.intersectTriangle(d,e,f,h.side!==THREE.DoubleSide,g)))return null;u.copy(g);u.applyMatrix4(a.matrixWorld);c=b.ray.origin.distanceTo(u);return c<b.near||c>b.far?null:{dist [...]
+object:a}}function c(c,d,e,g,k,m,p,u){f.fromArray(g,3*m);h.fromArray(g,3*p);l.fromArray(g,3*u);if(c=b(c,d,e,f,h,l,v))k&&(n.fromArray(k,2*m),q.fromArray(k,2*p),s.fromArray(k,2*u),c.uv=a(v,f,h,l,n,q,s)),c.face=new THREE.Face3(m,p,u,THREE.Triangle.normal(f,h,l)),c.faceIndex=m;return c}var d=new THREE.Matrix4,e=new THREE.Ray,g=new THREE.Sphere,f=new THREE.Vector3,h=new THREE.Vector3,l=new THREE.Vector3,k=new THREE.Vector3,m=new THREE.Vector3,p=new THREE.Vector3,n=new THREE.Vector2,q=new THRE [...]
+s=new THREE.Vector2,t=new THREE.Vector3,v=new THREE.Vector3,u=new THREE.Vector3;return function(u,t){var x=this.geometry,B=this.material;if(void 0!==B){null===x.boundingSphere&&x.computeBoundingSphere();var y=this.matrixWorld;g.copy(x.boundingSphere);g.applyMatrix4(y);if(!1!==u.ray.isIntersectionSphere(g)&&(d.getInverse(y),e.copy(u.ray).applyMatrix4(d),null===x.boundingBox||!1!==e.isIntersectionBox(x.boundingBox))){var z,A;if(x instanceof THREE.BufferGeometry){var J,F,B=x.index,y=x.attri [...]
+void 0!==y.uv&&(z=y.uv.array);if(null!==B)for(var y=B.array,C=0,N=y.length;C<N;C+=3){if(B=y[C],J=y[C+1],F=y[C+2],A=c(this,u,e,x,z,B,J,F))A.faceIndex=Math.floor(C/3),t.push(A)}else for(C=0,N=x.length;C<N;C+=9)if(B=C/3,J=B+1,F=B+2,A=c(this,u,e,x,z,B,J,F))A.index=B,t.push(A)}else if(x instanceof THREE.Geometry){var L,Q,y=B instanceof THREE.MeshFaceMaterial,C=!0===y?B.materials:null,N=x.vertices;J=x.faces;F=x.faceVertexUvs[0];0<F.length&&(z=F);for(var M=0,K=J.length;M<K;M++){var E=J[M];A=!0= [...]
+B;if(void 0!==A){F=N[E.a];L=N[E.b];Q=N[E.c];if(!0===A.morphTargets){A=x.morphTargets;var O=this.morphTargetInfluences;f.set(0,0,0);h.set(0,0,0);l.set(0,0,0);for(var T=0,H=A.length;T<H;T++){var R=O[T];if(0!==R){var G=A[T].vertices;f.addScaledVector(k.subVectors(G[E.a],F),R);h.addScaledVector(m.subVectors(G[E.b],L),R);l.addScaledVector(p.subVectors(G[E.c],Q),R)}}f.add(F);h.add(L);l.add(Q);F=f;L=h;Q=l}if(A=b(this,u,e,F,L,Q,v))z&&(O=z[M],n.copy(O[0]),q.copy(O[1]),s.copy(O[2]),A.uv=a(v,F,L,Q, [...]
+E,A.faceIndex=M,t.push(A)}}}}}}}();THREE.Mesh.prototype.clone=function(){return(new this.constructor(this.geometry,this.material)).copy(this)};THREE.Bone=function(a){THREE.Object3D.call(this);this.type="Bone";this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.constructor=THREE.Bone;THREE.Bone.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a);this.skin=a.skin;return this};
+THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(a=Math.sqrt(4*this.bones.length),a=THREE.Math.nextPowerOfTwo(Math.ceil(a)),this.boneTextureHeight=this.boneTextureWidth=a=Math.max(a,4),this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAF [...]
+this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton bonInverses is the wrong length."),this.boneInverses=[],b=0,a=this.bones.length;b<a;b++)this.boneInverses.push(new THREE.Matrix4)};
+THREE.Skeleton.prototype.calculateInverses=function(){this.boneInverses=[];for(var a=0,b=this.bones.length;a<b;a++){var c=new THREE.Matrix4;this.bones[a]&&c.getInverse(this.bones[a].matrixWorld);this.boneInverses.push(c)}};
+THREE.Skeleton.prototype.pose=function(){for(var a,b=0,c=this.bones.length;b<c;b++)(a=this.bones[b])&&a.matrixWorld.getInverse(this.boneInverses[b]);b=0;for(c=this.bones.length;b<c;b++)if(a=this.bones[b])a.parent?(a.matrix.getInverse(a.parent.matrixWorld),a.matrix.multiply(a.matrixWorld)):a.matrix.copy(a.matrixWorld),a.matrix.decompose(a.position,a.quaternion,a.scale)};
+THREE.Skeleton.prototype.update=function(){var a=new THREE.Matrix4;return function(){for(var b=0,c=this.bones.length;b<c;b++)a.multiplyMatrices(this.bones[b]?this.bones[b].matrixWorld:this.identityMatrix,this.boneInverses[b]),a.flattenToArrayOffset(this.boneMatrices,16*b);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}}();THREE.Skeleton.prototype.clone=function(){return new THREE.Skeleton(this.bones,this.boneInverses,this.useVertexTexture)};
+THREE.SkinnedMesh=function(a,b,c){THREE.Mesh.call(this,a,b);this.type="SkinnedMesh";this.bindMode="attached";this.bindMatrix=new THREE.Matrix4;this.bindMatrixInverse=new THREE.Matrix4;a=[];if(this.geometry&&void 0!==this.geometry.bones){for(var d,e=0,g=this.geometry.bones.length;e<g;++e)d=this.geometry.bones[e],b=new THREE.Bone(this),a.push(b),b.name=d.name,b.position.fromArray(d.pos),b.quaternion.fromArray(d.rotq),void 0!==d.scl&&b.scale.fromArray(d.scl);e=0;for(g=this.geometry.bones.le [...]
+this.geometry.bones[e],-1!==d.parent&&null!==d.parent?a[d.parent].add(a[e]):this.add(a[e])}this.normalizeSkinWeights();this.updateMatrixWorld(!0);this.bind(new THREE.Skeleton(a,void 0,c),this.matrixWorld)};THREE.SkinnedMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.SkinnedMesh.prototype.constructor=THREE.SkinnedMesh;
+THREE.SkinnedMesh.prototype.bind=function(a,b){this.skeleton=a;void 0===b&&(this.updateMatrixWorld(!0),this.skeleton.calculateInverses(),b=this.matrixWorld);this.bindMatrix.copy(b);this.bindMatrixInverse.getInverse(b)};THREE.SkinnedMesh.prototype.pose=function(){this.skeleton.pose()};
+THREE.SkinnedMesh.prototype.normalizeSkinWeights=function(){if(this.geometry instanceof THREE.Geometry)for(var a=0;a<this.geometry.skinIndices.length;a++){var b=this.geometry.skinWeights[a],c=1/b.lengthManhattan();Infinity!==c?b.multiplyScalar(c):b.set(1)}};
+THREE.SkinnedMesh.prototype.updateMatrixWorld=function(a){THREE.Mesh.prototype.updateMatrixWorld.call(this,!0);"attached"===this.bindMode?this.bindMatrixInverse.getInverse(this.matrixWorld):"detached"===this.bindMode?this.bindMatrixInverse.getInverse(this.bindMatrix):console.warn("THREE.SkinnedMesh unrecognized bindMode: "+this.bindMode)};THREE.SkinnedMesh.prototype.clone=function(){return(new this.constructor(this.geometry,this.material,this.useVertexTexture)).copy(this)};
+THREE.LOD=function(){THREE.Object3D.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]},objects:{get:function(){console.warn("THREE.LOD: .objects has been renamed to .levels.");return this.levels}}})};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.constructor=THREE.LOD;
+THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);b=Math.abs(b);for(var c=this.levels,d=0;d<c.length&&!(b<c[d].distance);d++);c.splice(d,0,{distance:b,object:a});this.add(a)};THREE.LOD.prototype.getObjectForDistance=function(a){for(var b=this.levels,c=1,d=b.length;c<d&&!(a<b[c].distance);c++);return b[c-1].object};
+THREE.LOD.prototype.raycast=function(){var a=new THREE.Vector3;return function(b,c){a.setFromMatrixPosition(this.matrixWorld);var d=b.ray.origin.distanceTo(a);this.getObjectForDistance(d).raycast(b,c)}}();
+THREE.LOD.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){var d=this.levels;if(1<d.length){a.setFromMatrixPosition(c.matrixWorld);b.setFromMatrixPosition(this.matrixWorld);c=a.distanceTo(b);d[0].object.visible=!0;for(var e=1,g=d.length;e<g;e++)if(c>=d[e].distance)d[e-1].object.visible=!1,d[e].object.visible=!0;else break;for(;e<g;e++)d[e].object.visible=!1}}}();
+THREE.LOD.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b<c;b++){var d=a[b];this.addLevel(d.object.clone(),d.distance)}return this};THREE.LOD.prototype.toJSON=function(a){a=THREE.Object3D.prototype.toJSON.call(this,a);a.object.levels=[];for(var b=this.levels,c=0,d=b.length;c<d;c++){var e=b[c];a.object.levels.push({object:e.object.uuid,distance:e.distance})}return a};
+THREE.Sprite=function(){var a=new Uint16Array([0,1,2,0,2,3]),b=new Float32Array([-.5,-.5,0,.5,-.5,0,.5,.5,0,-.5,.5,0]),c=new Float32Array([0,0,1,0,1,1,0,1]),d=new THREE.BufferGeometry;d.setIndex(new THREE.BufferAttribute(a,1));d.addAttribute("position",new THREE.BufferAttribute(b,3));d.addAttribute("uv",new THREE.BufferAttribute(c,2));return function(a){THREE.Object3D.call(this);this.type="Sprite";this.geometry=d;this.material=void 0!==a?a:new THREE.SpriteMaterial}}();THREE.Sprite.protot [...]
+THREE.Sprite.prototype.constructor=THREE.Sprite;THREE.Sprite.prototype.raycast=function(){var a=new THREE.Vector3;return function(b,c){a.setFromMatrixPosition(this.matrixWorld);var d=b.ray.distanceSqToPoint(a);d>this.scale.x*this.scale.y||c.push({distance:Math.sqrt(d),point:this.position,face:null,object:this})}}();THREE.Sprite.prototype.clone=function(){return(new this.constructor(this.material)).copy(this)};THREE.Particle=THREE.Sprite;
+THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype);THREE.LensFlare.prototype.constructor=THREE.LensFlare;
+THREE.LensFlare.prototype.add=function(a,b,c,d,e,g){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===g&&(g=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:0,opacity:g,color:e,blending:d})};
+THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a<b;a++)c=this.lensFlares[a],c.x=this.positionScreen.x+d*c.distance,c.y=this.positionScreen.y+e*c.distance,c.wantedRotation=c.x*Math.PI*.25,c.rotation+=.25*(c.wantedRotation-c.rotation)};
+THREE.LensFlare.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a);this.positionScreen.copy(a.positionScreen);this.customUpdateCallback=a.customUpdateCallback;for(var b=0,c=a.lensFlares.length;b<c;b++)this.lensFlares.push(a.lensFlares[b]);return this};THREE.Scene=function(){THREE.Object3D.call(this);this.type="Scene";this.overrideMaterial=this.fog=null;this.autoUpdate=!0};THREE.Scene.prototype=Object.create(THREE.Object3D.prototype);THREE.Scene.prototype.constructor=TH [...]
+THREE.Scene.prototype.copy=function(a){THREE.Object3D.prototype.copy.call(this,a);null!==a.fog&&(this.fog=a.fog.clone());null!==a.overrideMaterial&&(this.overrideMaterial=a.overrideMaterial.clone());this.autoUpdate=a.autoUpdate;this.matrixAutoUpdate=a.matrixAutoUpdate;return this};THREE.Fog=function(a,b,c){this.name="";this.color=new THREE.Color(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3};THREE.Fog.prototype.clone=function(){return new THREE.Fog(this.color.getHex(),this.near,t [...]
+THREE.FogExp2=function(a,b){this.name="";this.color=new THREE.Color(a);this.density=void 0!==b?b:2.5E-4};THREE.FogExp2.prototype.clone=function(){return new THREE.FogExp2(this.color.getHex(),this.density)};THREE.ShaderChunk={};THREE.ShaderChunk.alphamap_fragment="#ifdef USE_ALPHAMAP\n\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n";THREE.ShaderChunk.alphamap_pars_fragment="#ifdef USE_ALPHAMAP\n\n\tuniform sampler2D alphaMap;\n\n#endif\n";THREE.ShaderChunk.alphatest_fragme [...]
+THREE.ShaderChunk.aomap_fragment="#ifdef USE_AOMAP\n\n\ttotalAmbientLight *= ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n#endif\n";THREE.ShaderChunk.aomap_pars_fragment="#ifdef USE_AOMAP\n\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n\n#endif";THREE.ShaderChunk.begin_vertex="\nvec3 transformed = vec3( position );\n";THREE.ShaderChunk.beginnormal_vertex="\nvec3 objectNormal = vec3( normal );\n";THREE.ShaderChunk.bumpmap_pars_fragment="#ifdef USE_BUMPMA [...]
+THREE.ShaderChunk.color_fragment="#ifdef USE_COLOR\n\n\tdiffuseColor.rgb *= vColor;\n\n#endif";THREE.ShaderChunk.color_pars_fragment="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif\n";THREE.ShaderChunk.color_pars_vertex="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif";THREE.ShaderChunk.color_vertex="#ifdef USE_COLOR\n\n\tvColor.xyz = color.xyz;\n\n#endif";THREE.ShaderChunk.common="#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.44269 [...]
+THREE.ShaderChunk.defaultnormal_vertex="#ifdef FLIP_SIDED\n\n\tobjectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n";THREE.ShaderChunk.displacementmap_vertex="#ifdef USE_DISPLACEMENTMAP\n\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n\n#endif\n";THREE.ShaderChunk.displacementmap_pars_vertex="#ifdef USE_DISPLACEMENTMAP\n\n\tuniform sampler2D displacementMap;\n\tuniform float displace [...]
+THREE.ShaderChunk.emissivemap_fragment="#ifdef USE_EMISSIVEMAP\n\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\n\temissiveColor.rgb = inputToLinear( emissiveColor.rgb );\n\n\ttotalEmissiveLight *= emissiveColor.rgb;\n\n#endif\n";THREE.ShaderChunk.emissivemap_pars_fragment="#ifdef USE_EMISSIVEMAP\n\n\tuniform sampler2D emissiveMap;\n\n#endif\n";THREE.ShaderChunk.envmap_fragment="#ifdef USE_ENVMAP\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\ [...]
+THREE.ShaderChunk.envmap_pars_fragment="#ifdef USE_ENVMAP\n\n\tuniform float reflectivity;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tuniform float refractionRatio;\n\n\t#else\n\n\t\tvarying vec3 vReflect;\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.envmap_pars_vertex="#if defined( USE_ENVMAP ) && ! defined(  [...]
+THREE.ShaderChunk.envmap_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\n\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\n\t#else\n\n\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t#endif\n\ [...]
+THREE.ShaderChunk.fog_fragment="#ifdef USE_FOG\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n\t#else\n\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\n\t#endif\n\n\t#ifdef FOG_EXP2\n\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\n\n\t#else\n\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n\n\t#endif\n\t\n\toutgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif";
+THREE.ShaderChunk.fog_pars_fragment="#ifdef USE_FOG\n\n\tuniform vec3 fogColor;\n\n\t#ifdef FOG_EXP2\n\n\t\tuniform float fogDensity;\n\n\t#else\n\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n\n#endif";THREE.ShaderChunk.hemilight_fragment="#if MAX_HEMI_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n\t\tvec3 lightDir = hemisphereLightDirection[ i ];\n\n\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct  [...]
+THREE.ShaderChunk.lightmap_fragment="#ifdef USE_LIGHTMAP\n\n\ttotalAmbientLight += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\n#endif\n";THREE.ShaderChunk.lightmap_pars_fragment="#ifdef USE_LIGHTMAP\n\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n\n#endif";THREE.ShaderChunk.lights_lambert_pars_vertex="#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\ [...]
+THREE.ShaderChunk.lights_lambert_vertex="vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack = vec3( 0.0 );\n\n#endif\n\nvec3 normal = normalize( transformedNormal );\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec3 lightColor = pointLightColor[ i ];\n\n\t\tvec3 lVector = pointLightPosition[ i ] - mvPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointL [...]
+THREE.ShaderChunk.lights_phong_fragment="vec3 viewDir = normalize( vViewPosition );\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec3 lightColor = pointLightColor[ i ];\n\n\t\tvec3 lightPosition = pointLightPosition[ i ];\n\t\tvec3 lVector = lightPosition + vViewPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\n\t\tfloat attenuation = calcLightAttenuatio [...]
+THREE.ShaderChunk.lights_phong_pars_fragment="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tun [...]
+THREE.ShaderChunk.lights_phong_pars_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\n#endif\n";THREE.ShaderChunk.lights_phong_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP )\n\n\tvWorldPosition = worldPosition.xyz;\n\n#endif\n";THREE.ShaderChunk.linear_to_gamma_fragment="\n\toutgoingLight = linearToOutput( outgoingLight );\n";
+THREE.ShaderChunk.logdepthbuf_fragment="#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif";THREE.ShaderChunk.logdepthbuf_pars_fragment="#ifdef USE_LOGDEPTHBUF\n\n\tuniform float logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.logdepthbuf_pars_vertex="#ifdef USE_LOGDEPTHBUF\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvarying float vFragD [...]
+THREE.ShaderChunk.logdepthbuf_vertex="#ifdef USE_LOGDEPTHBUF\n\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.map_fragment="#ifdef USE_MAP\n\n\tvec4 texelColor = texture2D( map, vUv );\n\n\ttexelColor.xyz = inputToLinear( texelColor.xyz );\n\n\tdiffuseColor *= texelColor;\n\n [...]
+THREE.ShaderChunk.map_pars_fragment="#ifdef USE_MAP\n\n\tuniform sampler2D map;\n\n#endif";THREE.ShaderChunk.map_particle_fragment="#ifdef USE_MAP\n\n\tdiffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n";THREE.ShaderChunk.map_particle_pars_fragment="#ifdef USE_MAP\n\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n\n#endif\n";THREE.ShaderChunk.morphnormal_vertex="#ifdef USE_MORPHNORMALS\n\n\tobjectNorm [...]
+THREE.ShaderChunk.morphtarget_pars_vertex="#ifdef USE_MORPHTARGETS\n\n\t#ifndef USE_MORPHNORMALS\n\n\tuniform float morphTargetInfluences[ 8 ];\n\n\t#else\n\n\tuniform float morphTargetInfluences[ 4 ];\n\n\t#endif\n\n#endif";THREE.ShaderChunk.morphtarget_vertex="#ifdef USE_MORPHTARGETS\n\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * mor [...]
+THREE.ShaderChunk.normal_phong_fragment="#ifndef FLAT_SHADED\n\n\tvec3 normal = normalize( vNormal );\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n\t#endif\n\n#else\n\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\n#ifdef USE_NORMALMAP\n\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n\tnormal = perturbNormal [...]
+THREE.ShaderChunk.normalmap_pars_fragment="#ifdef USE_NORMALMAP\n\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\n\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\n\t\tvec3 mapN = [...]
+THREE.ShaderChunk.project_vertex="#ifdef USE_SKINNING\n\n\tvec4 mvPosition = modelViewMatrix * skinned;\n\n#else\n\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n";THREE.ShaderChunk.shadowmap_fragment="#ifdef USE_SHADOWMAP\n\n\tfor ( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tfloat texelSizeY =  1.0 / shadowMapSize[ i ].y;\n\n\t\tfloat shadow = 0.0;\n\n#if defined( POINT_LIGHT_SHADOWS )\n\n\t\tbool isPointLight [...]
+THREE.ShaderChunk.shadowmap_pars_fragment="#ifdef USE_SHADOWMAP\n\n\tuniform sampler2D shadowMap[ MAX_SHADOWS ];\n\tuniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n\tuniform float shadowDarkness[ MAX_SHADOWS ];\n\tuniform float shadowBias[ MAX_SHADOWS ];\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n\tfloat unpackDepth( const in vec4 rgba_depth ) {\n\n\t\tconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n\t\tfloat depth = dot( r [...]
+THREE.ShaderChunk.shadowmap_pars_vertex="#ifdef USE_SHADOWMAP\n\n\tuniform float shadowDarkness[ MAX_SHADOWS ];\n\tuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n#endif";THREE.ShaderChunk.shadowmap_vertex="#ifdef USE_SHADOWMAP\n\n\tfor ( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n\t}\n\n#endif";THREE.ShaderChunk.skinbase_vertex="#ifdef USE_SKINNING\n\n\tmat4 boneMatX = getBoneMatrix( s [...]
+THREE.ShaderChunk.skinning_pars_vertex="#ifdef USE_SKINNING\n\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\n\t#ifdef BONE_TEXTURE\n\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\n\t\tmat4 getBoneMatrix( const in float i ) {\n\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\n\t\t\tfloat dx = 1.0 / float( boneTextureWi [...]
+THREE.ShaderChunk.skinning_vertex="#ifdef USE_SKINNING\n\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned  = bindMatrixInverse * skinned;\n\n#endif\n";THREE.ShaderChunk.skinnormal_vertex="#ifdef USE_SKINNING\n\n\tmat4 skinMatrix  [...]
+THREE.ShaderChunk.specularmap_fragment="float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n\n#else\n\n\tspecularStrength = 1.0;\n\n#endif";THREE.ShaderChunk.specularmap_pars_fragment="#ifdef USE_SPECULARMAP\n\n\tuniform sampler2D specularMap;\n\n#endif";THREE.ShaderChunk.uv2_pars_fragment="#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tvarying vec2 vUv2;\n\n#endif";
+THREE.ShaderChunk.uv2_pars_vertex="#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\n#endif";THREE.ShaderChunk.uv2_vertex="#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tvUv2 = uv2;\n\n#endif";THREE.ShaderChunk.uv_pars_fragment="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n\tvarying vec2 vUv;\n\n#endif";
+THREE.ShaderChunk.uv_pars_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n\n#endif\n";THREE.ShaderChunk.uv_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n\tvUv = uv * offsetRepeat.zw + o [...]
+THREE.ShaderChunk.worldpos_vertex="#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n\t#ifdef USE_SKINNING\n\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\n\t#else\n\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\n\t#endif\n\n#endif\n";
+THREE.UniformsUtils={merge:function(a){for(var b={},c=0;c<a.length;c++){var d=this.clone(a[c]),e;for(e in d)b[e]=d[e]}return b},clone:function(a){var b={},c;for(c in a){b[c]={};for(var d in a[c]){var e=a[c][d];e instanceof THREE.Color||e instanceof THREE.Vector2||e instanceof THREE.Vector3||e instanceof THREE.Vector4||e instanceof THREE.Matrix3||e instanceof THREE.Matrix4||e instanceof THREE.Texture?b[c][d]=e.clone():Array.isArray(e)?b[c][d]=e.slice():b[c][d]=e}}return b}};
+THREE.UniformsLib={common:{diffuse:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},specularMap:{type:"t",value:null},alphaMap:{type:"t",value:null},envMap:{type:"t",value:null},flipEnvMap:{type:"f",value:-1},reflectivity:{type:"f",value:1},refractionRatio:{type:"f",value:.98}},aomap:{aoMap:{type:"t",value:null},aoMapIntensity:{type:"f",value:1}},lightmap:{lightMap:{type:"t",value:nul [...]
+value:1}},emissivemap:{emissiveMap:{type:"t",value:null}},bumpmap:{bumpMap:{type:"t",value:null},bumpScale:{type:"f",value:1}},normalmap:{normalMap:{type:"t",value:null},normalScale:{type:"v2",value:new THREE.Vector2(1,1)}},displacementmap:{displacementMap:{type:"t",value:null},displacementScale:{type:"f",value:1},displacementBias:{type:"f",value:0}},fog:{fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(167 [...]
+lights:{ambientLightColor:{type:"fv",value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},hemisphereLightDirection:{type:"fv",value:[]},hemisphereLightSkyColor:{type:"fv",value:[]},hemisphereLightGroundColor:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightDistance:{type:"fv1",value:[]},pointLightDecay:{type:"fv1",value:[]},spotLightColor:{type:"fv",value:[]},spotLightPosition:{type: [...]
+spotLightDirection:{type:"fv",value:[]},spotLightDistance:{type:"fv1",value:[]},spotLightAngleCos:{type:"fv1",value:[]},spotLightExponent:{type:"fv1",value:[]},spotLightDecay:{type:"fv1",value:[]}},points:{psColor:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},size:{type:"f",value:1},scale:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type: [...]
+fogColor:{type:"c",value:new THREE.Color(16777215)}},shadowmap:{shadowMap:{type:"tv",value:[]},shadowMapSize:{type:"v2v",value:[]},shadowBias:{type:"fv1",value:[]},shadowDarkness:{type:"fv1",value:[]},shadowMatrix:{type:"m4v",value:[]}}};
+THREE.ShaderLib={basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.aomap,THREE.UniformsLib.fog,THREE.UniformsLib.shadowmap]),vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.uv_pars_vertex,THREE.ShaderChunk.uv2_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_p [...]
+"void main() {",THREE.ShaderChunk.uv_vertex,THREE.ShaderChunk.uv2_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.skinbase_vertex,"\t#ifdef USE_ENVMAP",THREE.ShaderChunk.beginnormal_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"\t#endif",THREE.ShaderChunk.begin_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex, [...]
+THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.uv_pars_fragment,THREE.ShaderChunk.uv2_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment,THREE.ShaderChunk.aomap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.sha [...]
+THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tvec3 totalAmbientLight = vec3( 1.0 );\n\tvec3 shadowMask = vec3( 1.0 );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.Shader [...]
+THREE.ShaderChunk.shadowmap_fragment,"\toutgoingLight = diffuseColor.rgb * totalAmbientLight * shadowMask;",THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{emissive:{type:"c",value:new THREE.Color(0)}}]),vertexSh [...]
+THREE.ShaderChunk.common,THREE.ShaderChunk.uv_pars_vertex,THREE.ShaderChunk.uv2_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_lambert_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.uv_vertex,THREE.ShaderChunk.uv2_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChu [...]
+THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,THREE.ShaderChunk.begin_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:[" [...]
+THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.uv_pars_fragment,THREE.ShaderChunk.uv2_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = v [...]
+THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.shadowmap_fragment,"\t#ifdef DOUBLE_SIDED\n\t\tif ( gl_FrontFacing )\n\t\t\toutgoingLight += diffuseColor.rgb * ( vLightFront * shadowMask + totalAmbientLight ) + emissive;\n\t\telse\n\t\t\toutgoingLight += diffuseColor.rgb * ( vLightBack * shadowMask + total [...]
+THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.aomap,THREE.UniformsLib.lightmap,THREE.UniformsLib.emissivemap,THREE.UniformsLib.bumpmap,THREE.UniformsLib.normalmap,THREE.UniformsLib.displacementmap,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowma [...]
+value:new THREE.Color(0)},specular:{type:"c",value:new THREE.Color(1118481)},shininess:{type:"f",value:30}}]),vertexShader:["#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif",THREE.ShaderChunk.common,THREE.ShaderChunk.uv_pars_vertex,THREE.ShaderChunk.uv2_pars_vertex,THREE.ShaderChunk.displacementmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_phong_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChu [...]
+THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.uv_vertex,THREE.ShaderChunk.uv2_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.beginnormal_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif",THREE.Sha [...]
+THREE.ShaderChunk.displacementmap_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"\tvViewPosition = - mvPosition.xyz;",THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float  [...]
+THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.uv_pars_fragment,THREE.ShaderChunk.uv2_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment,THREE.ShaderChunk.aomap_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.emissivemap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.lights_phong_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragm [...]
+THREE.ShaderChunk.normalmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tvec3 totalAmbientLight = ambientLightColor;\n\tvec3 totalEmissiveLight = emissive;\n\tvec3 shadowMask = vec3( 1.0 );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,T [...]
+THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.normal_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.hemilight_fragment,THREE.ShaderChunk.aomap_fragment,THREE.ShaderChunk.emissivemap_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.shadowmap_fragment,"totalDiffuseLight *= shadowMask;\ntotalSpecularLight *= shadowMask;\n#ifdef METAL\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) * specular + totalSpecularL [...]
+THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},points:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.points,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main [...]
+"\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\tgl_Position = projectionMatrix * mvPosition;",THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_f [...]
+THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( psColor, opacity );\n\tvec3 shadowMask = vec3( 1.0 );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.shadowmap_fragment,"\toutgoingLight = diffuseColor.rgb * shadowMask [...]
+"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},dashed:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,{scale:{type:"f",value:1},dashSize:{type:"f",value:1},totalSize:{type:"f",value:2}}]),vertexShader:["uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.color_ [...]
+THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = ve [...]
+THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.color_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.begin_vertex,THREE.Shade [...]
+THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mF [...]
+normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvNormal = normalize( normalMatrix * normal );",THREE.ShaderChunk.begin_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChun [...]
+THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelVie [...]
+THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},equirect:{uniforms:{tEquirect:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 v [...]
+THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\nvec3 direction = normalize( vW [...]
+THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.begin_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShade [...]
+THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_ [...]
+distanceRGBA:{uniforms:{lightPos:{type:"v3",value:new THREE.Vector3(0,0,0)}},vertexShader:["varying vec4 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.begin_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.project_vertex,THREE.ShaderChunk.worldpos_vertex,"vWorldPosition = worldPosition;\n}"].join("\ [...]
+THREE.ShaderChunk.common,"vec4 pack1K ( float depth ) {\n   depth /= 1000.0;\n   const vec4 bitSh = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bitMsk = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = fract( depth * bitSh );\n\tres -= res.xxyz * bitMsk;\n\treturn res; \n}\nfloat unpack1K ( vec4 color ) {\n\tconst vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n\treturn dot( color, bitSh ) * 10 [...]
+THREE.WebGLRenderer=function(a){function b(a,b,c,d){!0===G&&(a*=d,b*=d,c*=d);r.clearColor(a,b,c,d)}function c(){I.init();r.viewport(na,oa,pa,qa);b(U.r,U.g,U.b,X)}function d(){ra=Aa=null;sa="";ta=-1;wa=!0;I.reset()}function e(a){a.preventDefault();d();c();W.clear()}function g(a){a=a.target;a.removeEventListener("dispose",g);a:{var b=W.get(a);if(a.image&&b.__image__webglTextureCube)r.deleteTexture(b.__image__webglTextureCube);else{if(void 0===b.__webglInit)break a;r.deleteTexture(b.__webgl [...]
+function f(a){a=a.target;a.removeEventListener("dispose",f);var b=W.get(a),c=W.get(a.texture);if(a&&void 0!==c.__webglTexture){r.deleteTexture(c.__webglTexture);if(a instanceof THREE.WebGLRenderTargetCube)for(c=0;6>c;c++)r.deleteFramebuffer(b.__webglFramebuffer[c]),r.deleteRenderbuffer(b.__webglRenderbuffer[c]);else r.deleteFramebuffer(b.__webglFramebuffer),r.deleteRenderbuffer(b.__webglRenderbuffer);W.delete(a.texture);W.delete(a)}la.textures--}function h(a){a=a.target;a.removeEventList [...]
+h);l(a);W.delete(a)}function l(a){var b=W.get(a).program;a.program=void 0;void 0!==b&&ua.releaseProgram(b)}function k(a,b){return b[0]-a[0]}function m(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.material.id!==b.material.id?a.material.id-b.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function p(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function n(a,b,c,d,e [...]
+(d=Z,f=++fa):(d=ca,f=++ga);f=d[f];void 0!==f?(f.id=a.id,f.object=a,f.geometry=b,f.material=c,f.z=V.z,f.group=e):(f={id:a.id,object:a,geometry:b,material:c,z:V.z,group:e},d.push(f))}function q(a,b){if(!1!==a.visible){if(0!==(a.channels.mask&b.channels.mask))if(a instanceof THREE.Light)da.push(a);else if(a instanceof THREE.Sprite)ea.push(a);else if(a instanceof THREE.LensFlare)ja.push(a);else if(a instanceof THREE.ImmediateRenderObject)!0===aa.sortObjects&&(V.setFromMatrixPosition(a.matrix [...]
+n(a,null,a.material,V.z,null);else if(a instanceof THREE.Mesh||a instanceof THREE.Line||a instanceof THREE.Points)if(a instanceof THREE.SkinnedMesh&&a.skeleton.update(),!1===a.frustumCulled||!0===Ba.intersectsObject(a)){var c=a.material;if(!0===c.visible){!0===aa.sortObjects&&(V.setFromMatrixPosition(a.matrixWorld),V.applyProjection(xa));var d=va.update(a);if(c instanceof THREE.MeshFaceMaterial)for(var e=d.groups,f=c.materials,c=0,g=e.length;c<g;c++){var h=e[c],l=f[h.materialIndex];!0=== [...]
+n(a,d,l,V.z,h)}else n(a,d,c,V.z,null)}}d=a.children;c=0;for(g=d.length;c<g;c++)q(d[c],b)}}function s(a,b,c,d,e){for(var f=0,g=a.length;f<g;f++){var h=a[f],l=h.object,k=h.geometry,n=void 0===e?h.material:e,h=h.group;l.modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,l.matrixWorld);l.normalMatrix.getNormalMatrix(l.modelViewMatrix);if(l instanceof THREE.ImmediateRenderObject){t(n);var m=v(b,c,d,n,l);sa="";l.render(function(a){aa.renderBufferImmediate(a,m,n)})}else aa.renderBufferDirect [...]
+n,l,h)}}function t(a){a.side!==THREE.DoubleSide?I.enable(r.CULL_FACE):I.disable(r.CULL_FACE);I.setFlipSided(a.side===THREE.BackSide);!0===a.transparent?I.setBlending(a.blending,a.blendEquation,a.blendSrc,a.blendDst,a.blendEquationAlpha,a.blendSrcAlpha,a.blendDstAlpha):I.setBlending(THREE.NoBlending);I.setDepthFunc(a.depthFunc);I.setDepthTest(a.depthTest);I.setDepthWrite(a.depthWrite);I.setColorWrite(a.colorWrite);I.setPolygonOffset(a.polygonOffset,a.polygonOffsetFactor,a.polygonOffsetUni [...]
+b,c,d,e){ya=0;var f=W.get(d);if(d.needsUpdate||!f.program){a:{var g=W.get(d),k=ua.getParameters(d,b,c,e),n=ua.getProgramCode(d,k),m=g.program,q=!0;if(void 0===m)d.addEventListener("dispose",h);else if(m.code!==n)l(d);else if(void 0!==k.shaderID)break a;else q=!1;q&&(k.shaderID?(m=THREE.ShaderLib[k.shaderID],g.__webglShader={name:d.type,uniforms:THREE.UniformsUtils.clone(m.uniforms),vertexShader:m.vertexShader,fragmentShader:m.fragmentShader}):g.__webglShader={name:d.type,uniforms:d.unifo [...]
+fragmentShader:d.fragmentShader},d.__webglShader=g.__webglShader,m=ua.acquireProgram(d,k,n),g.program=m,d.program=m);k=m.getAttributes();if(d.morphTargets)for(n=d.numSupportedMorphTargets=0;n<aa.maxMorphTargets;n++)0<=k["morphTarget"+n]&&d.numSupportedMorphTargets++;if(d.morphNormals)for(n=d.numSupportedMorphNormals=0;n<aa.maxMorphNormals;n++)0<=k["morphNormal"+n]&&d.numSupportedMorphNormals++;g.uniformsList=[];var k=g.program.getUniforms(),p;for(p in g.__webglShader.uniforms)(n=k[p])&&g [...]
+n])}d.needsUpdate=!1}n=m=q=!1;g=f.program;p=g.getUniforms();k=f.__webglShader.uniforms;g.id!==Aa&&(r.useProgram(g.program),Aa=g.id,n=m=q=!0);d.id!==ta&&(-1===ta&&(n=!0),ta=d.id,m=!0);if(q||a!==ra)r.uniformMatrix4fv(p.projectionMatrix,!1,a.projectionMatrix.elements),ha.logarithmicDepthBuffer&&r.uniform1f(p.logDepthBufFC,2/(Math.log(a.far+1)/Math.LN2)),a!==ra&&(ra=a),(d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&void 0!==p.cameraPosition&&(V.setFromMa [...]
+r.uniform3f(p.cameraPosition,V.x,V.y,V.z)),(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshBasicMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&void 0!==p.viewMatrix&&r.uniformMatrix4fv(p.viewMatrix,!1,a.matrixWorldInverse.elements);d.skinning&&(e.bindMatrix&&void 0!==p.bindMatrix&&r.uniformMatrix4fv(p.bindMatrix,!1,e.bindMatrix.elements),e.bindMatrixInverse&&void 0!==p.bindMatrixInverse&&r.uniformMatrix4fv(p.bindMatrixInver [...]
+ha.floatVertexTextures&&e.skeleton&&e.skeleton.useVertexTexture?(void 0!==p.boneTexture&&(q=w(),r.uniform1i(p.boneTexture,q),aa.setTexture(e.skeleton.boneTexture,q)),void 0!==p.boneTextureWidth&&r.uniform1i(p.boneTextureWidth,e.skeleton.boneTextureWidth),void 0!==p.boneTextureHeight&&r.uniform1i(p.boneTextureHeight,e.skeleton.boneTextureHeight)):e.skeleton&&e.skeleton.boneMatrices&&void 0!==p.boneGlobalMatrices&&r.uniformMatrix4fv(p.boneGlobalMatrices,!1,e.skeleton.boneMatrices));if(m){c [...]
+(k.fogColor.value=c.color,c instanceof THREE.Fog?(k.fogNear.value=c.near,k.fogFar.value=c.far):c instanceof THREE.FogExp2&&(k.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(wa){var n=!0,s,t=q=0,x=0,v,F,C,y=Ca,E=a.matrixWorldInverse,B=y.directional.colors,K=y.directional.positions,O=y.point.colors,N=y.point.positions,M=y.point.distances,G=y.point.decays,J=y.spot.colors,H=y.spot.positions,Q=y.spot.distances,I=y.spo [...]
+da=y.spot.anglesCos,T=y.spot.exponents,R=y.spot.decays,Z=y.hemi.skyColors,ga=y.hemi.groundColors,S=y.hemi.positions,ca=0,U=0,ea=0,fa=0,ja=0,ma=0,X=0,$=0,ba=s=0;c=C=ba=0;for(m=b.length;c<m;c++)s=b[c],v=s.color,F=s.intensity,C=s.distance,s instanceof THREE.AmbientLight?s.visible&&(q+=v.r,t+=v.g,x+=v.b):s instanceof THREE.DirectionalLight?(ja+=1,s.visible&&(Y.setFromMatrixPosition(s.matrixWorld),V.setFromMatrixPosition(s.target.matrixWorld),Y.sub(V),Y.transformDirection(E),s=3*ca,K[s+0]=Y.x [...]
+K[s+2]=Y.z,D(B,s,v,F),ca+=1)):s instanceof THREE.PointLight?(ma+=1,s.visible&&(ba=3*U,D(O,ba,v,F),V.setFromMatrixPosition(s.matrixWorld),V.applyMatrix4(E),N[ba+0]=V.x,N[ba+1]=V.y,N[ba+2]=V.z,M[U]=C,G[U]=0===s.distance?0:s.decay,U+=1)):s instanceof THREE.SpotLight?(X+=1,s.visible&&(ba=3*ea,D(J,ba,v,F),Y.setFromMatrixPosition(s.matrixWorld),V.copy(Y).applyMatrix4(E),H[ba+0]=V.x,H[ba+1]=V.y,H[ba+2]=V.z,Q[ea]=C,V.setFromMatrixPosition(s.target.matrixWorld),Y.sub(V),Y.transformDirection(E),I[ [...]
+I[ba+1]=Y.y,I[ba+2]=Y.z,da[ea]=Math.cos(s.angle),T[ea]=s.exponent,R[ea]=0===s.distance?0:s.decay,ea+=1)):s instanceof THREE.HemisphereLight&&($+=1,s.visible&&(Y.setFromMatrixPosition(s.matrixWorld),Y.transformDirection(E),C=3*fa,S[C+0]=Y.x,S[C+1]=Y.y,S[C+2]=Y.z,v=s.color,s=s.groundColor,D(Z,C,v,F),D(ga,C,s,F),fa+=1));c=3*ca;for(m=Math.max(B.length,3*ja);c<m;c++)B[c]=0;c=3*U;for(m=Math.max(O.length,3*ma);c<m;c++)O[c]=0;c=3*ea;for(m=Math.max(J.length,3*X);c<m;c++)J[c]=0;c=3*fa;for(m=Math.m [...]
+3*$);c<m;c++)Z[c]=0;c=3*fa;for(m=Math.max(ga.length,3*$);c<m;c++)ga[c]=0;y.directional.length=ca;y.point.length=U;y.spot.length=ea;y.hemi.length=fa;y.ambient[0]=q;y.ambient[1]=t;y.ambient[2]=x;wa=!1}n?(n=Ca,k.ambientLightColor.value=n.ambient,k.directionalLightColor.value=n.directional.colors,k.directionalLightDirection.value=n.directional.positions,k.pointLightColor.value=n.point.colors,k.pointLightPosition.value=n.point.positions,k.pointLightDistance.value=n.point.distances,k.pointLigh [...]
+n.point.decays,k.spotLightColor.value=n.spot.colors,k.spotLightPosition.value=n.spot.positions,k.spotLightDistance.value=n.spot.distances,k.spotLightDirection.value=n.spot.directions,k.spotLightAngleCos.value=n.spot.anglesCos,k.spotLightExponent.value=n.spot.exponents,k.spotLightDecay.value=n.spot.decays,k.hemisphereLightSkyColor.value=n.hemi.skyColors,k.hemisphereLightGroundColor.value=n.hemi.groundColors,k.hemisphereLightDirection.value=n.hemi.positions,u(k,!0)):u(k,!1)}if(d instanceof [...]
+d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){k.opacity.value=d.opacity;k.diffuse.value=d.color;d.emissive&&(k.emissive.value=d.emissive);k.map.value=d.map;k.specularMap.value=d.specularMap;k.alphaMap.value=d.alphaMap;d.aoMap&&(k.aoMap.value=d.aoMap,k.aoMapIntensity.value=d.aoMapIntensity);var P;d.map?P=d.map:d.specularMap?P=d.specularMap:d.displacementMap?P=d.displacementMap:d.normalMap?P=d.normalMap:d.bumpMap?P=d.bumpMap:d.alphaMap?P=d.alphaMap:d.emissiv [...]
+d.emissiveMap);void 0!==P&&(P instanceof THREE.WebGLRenderTarget&&(P=P.texture),n=P.offset,P=P.repeat,k.offsetRepeat.value.set(n.x,n.y,P.x,P.y));k.envMap.value=d.envMap;k.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;k.reflectivity.value=d.reflectivity;k.refractionRatio.value=d.refractionRatio}d instanceof THREE.LineBasicMaterial?(k.diffuse.value=d.color,k.opacity.value=d.opacity):d instanceof THREE.LineDashedMaterial?(k.diffuse.value=d.color,k.opacity.value=d.opa [...]
+d.dashSize,k.totalSize.value=d.dashSize+d.gapSize,k.scale.value=d.scale):d instanceof THREE.PointsMaterial?(k.psColor.value=d.color,k.opacity.value=d.opacity,k.size.value=d.size,k.scale.value=L.height/2,k.map.value=d.map,null!==d.map&&(a=d.map.offset,P=d.map.repeat,k.offsetRepeat.value.set(a.x,a.y,P.x,P.y))):d instanceof THREE.MeshPhongMaterial?(k.specular.value=d.specular,k.shininess.value=Math.max(d.shininess,1E-4),d.lightMap&&(k.lightMap.value=d.lightMap,k.lightMapIntensity.value=d.li [...]
+d.emissiveMap&&(k.emissiveMap.value=d.emissiveMap),d.bumpMap&&(k.bumpMap.value=d.bumpMap,k.bumpScale.value=d.bumpScale),d.normalMap&&(k.normalMap.value=d.normalMap,k.normalScale.value.copy(d.normalScale)),d.displacementMap&&(k.displacementMap.value=d.displacementMap,k.displacementScale.value=d.displacementScale,k.displacementBias.value=d.displacementBias)):d instanceof THREE.MeshDepthMaterial?(k.mNear.value=a.near,k.mFar.value=a.far,k.opacity.value=d.opacity):d instanceof THREE.MeshNorma [...]
+(k.opacity.value=d.opacity);if(e.receiveShadow&&!d._shadowPass&&k.shadowMatrix)for(a=d=0,P=b.length;a<P;a++)n=b[a],!0===n.castShadow&&(n instanceof THREE.PointLight||n instanceof THREE.SpotLight||n instanceof THREE.DirectionalLight)&&(c=n.shadow,n instanceof THREE.PointLight?(V.setFromMatrixPosition(n.matrixWorld).negate(),c.matrix.identity().setPosition(V),k.shadowDarkness.value[d]=-c.darkness):k.shadowDarkness.value[d]=c.darkness,k.shadowMatrix.value[d]=c.matrix,k.shadowMap.value[d]=c. [...]
+c.mapSize,k.shadowBias.value[d]=c.bias,d++);b=f.uniformsList;f=0;for(d=b.length;f<d;f++)if(a=b[f][0],!1!==a.needsUpdate)switch(k=a.type,c=a.value,P=b[f][1],k){case "1i":r.uniform1i(P,c);break;case "1f":r.uniform1f(P,c);break;case "2f":r.uniform2f(P,c[0],c[1]);break;case "3f":r.uniform3f(P,c[0],c[1],c[2]);break;case "4f":r.uniform4f(P,c[0],c[1],c[2],c[3]);break;case "1iv":r.uniform1iv(P,c);break;case "3iv":r.uniform3iv(P,c);break;case "1fv":r.uniform1fv(P,c);break;case "2fv":r.uniform2fv( [...]
+case "3fv":r.uniform3fv(P,c);break;case "4fv":r.uniform4fv(P,c);break;case "Matrix3fv":r.uniformMatrix3fv(P,!1,c);break;case "Matrix4fv":r.uniformMatrix4fv(P,!1,c);break;case "i":r.uniform1i(P,c);break;case "f":r.uniform1f(P,c);break;case "v2":r.uniform2f(P,c.x,c.y);break;case "v3":r.uniform3f(P,c.x,c.y,c.z);break;case "v4":r.uniform4f(P,c.x,c.y,c.z,c.w);break;case "c":r.uniform3f(P,c.r,c.g,c.b);break;case "iv1":r.uniform1iv(P,c);break;case "iv":r.uniform3iv(P,c);break;case "fv1":r.unifo [...]
+break;case "fv":r.uniform3fv(P,c);break;case "v2v":void 0===a._array&&(a._array=new Float32Array(2*c.length));m=k=0;for(n=c.length;k<n;k++,m+=2)a._array[m+0]=c[k].x,a._array[m+1]=c[k].y;r.uniform2fv(P,a._array);break;case "v3v":void 0===a._array&&(a._array=new Float32Array(3*c.length));m=k=0;for(n=c.length;k<n;k++,m+=3)a._array[m+0]=c[k].x,a._array[m+1]=c[k].y,a._array[m+2]=c[k].z;r.uniform3fv(P,a._array);break;case "v4v":void 0===a._array&&(a._array=new Float32Array(4*c.length));m=k=0;f [...]
+n;k++,m+=4)a._array[m+0]=c[k].x,a._array[m+1]=c[k].y,a._array[m+2]=c[k].z,a._array[m+3]=c[k].w;r.uniform4fv(P,a._array);break;case "m3":r.uniformMatrix3fv(P,!1,c.elements);break;case "m3v":void 0===a._array&&(a._array=new Float32Array(9*c.length));k=0;for(n=c.length;k<n;k++)c[k].flattenToArrayOffset(a._array,9*k);r.uniformMatrix3fv(P,!1,a._array);break;case "m4":r.uniformMatrix4fv(P,!1,c.elements);break;case "m4v":void 0===a._array&&(a._array=new Float32Array(16*c.length));k=0;for(n=c.le [...]
+16*k);r.uniformMatrix4fv(P,!1,a._array);break;case "t":m=w();r.uniform1i(P,m);if(!c)continue;c instanceof THREE.CubeTexture||Array.isArray(c.image)&&6===c.image.length?z(c,m):c instanceof THREE.WebGLRenderTargetCube?A(c.texture,m):c instanceof THREE.WebGLRenderTarget?aa.setTexture(c.texture,m):aa.setTexture(c,m);break;case "tv":void 0===a._array&&(a._array=[]);k=0;for(n=a.value.length;k<n;k++)a._array[k]=w();r.uniform1iv(P,a._array);k=0;for(n=a.value.length;k<n;k++)c=a.value[k],m=a._arra [...]
+THREE.CubeTexture||c.image instanceof Array&&6===c.image.length?z(c,m):c instanceof THREE.WebGLRenderTarget?aa.setTexture(c.texture,m):c instanceof THREE.WebGLRenderTargetCube?A(c.texture,m):aa.setTexture(c,m));break;default:console.warn("THREE.WebGLRenderer: Unknown uniform type: "+k)}}r.uniformMatrix4fv(p.modelViewMatrix,!1,e.modelViewMatrix.elements);p.normalMatrix&&r.uniformMatrix3fv(p.normalMatrix,!1,e.normalMatrix.elements);void 0!==p.modelMatrix&&r.uniformMatrix4fv(p.modelMatrix,! [...]
+return g}function u(a,b){a.ambientLightColor.needsUpdate=b;a.directionalLightColor.needsUpdate=b;a.directionalLightDirection.needsUpdate=b;a.pointLightColor.needsUpdate=b;a.pointLightPosition.needsUpdate=b;a.pointLightDistance.needsUpdate=b;a.pointLightDecay.needsUpdate=b;a.spotLightColor.needsUpdate=b;a.spotLightPosition.needsUpdate=b;a.spotLightDistance.needsUpdate=b;a.spotLightDirection.needsUpdate=b;a.spotLightAngleCos.needsUpdate=b;a.spotLightExponent.needsUpdate=b;a.spotLightDecay. [...]
+b;a.hemisphereLightSkyColor.needsUpdate=b;a.hemisphereLightGroundColor.needsUpdate=b;a.hemisphereLightDirection.needsUpdate=b}function w(){var a=ya;a>=ha.maxTextures&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+ha.maxTextures);ya+=1;return a}function D(a,b,c,d){a[b+0]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function x(a,b,c){c?(r.texParameteri(a,r.TEXTURE_WRAP_S,N(b.wrapS)),r.texParameteri(a,r.TEXTURE_WRAP_T,N(b.wrapT)),r.texParameteri(a,r.TEXTUR [...]
+N(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,N(b.minFilter))):(r.texParameteri(a,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(a,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.",b),r.texParameteri(a,r.TEXTURE_MAG_FILTER,C(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,C(b [...]
+b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.",b));!(c=S.get("EXT_texture_filter_anisotropic"))||b.type===THREE.FloatType&&null===S.get("OES_texture_float_linear")||b.type===THREE.HalfFloatType&&null===S.get("OES_texture_half_float_linear")||!(1<b.anisotropy||W.get(b).__currentAnisotropy)||(r.texParameterf(a,c.TEXTURE_MAX_ANI [...]
+Math.min(b.anisotropy,aa.getMaxAnisotropy())),W.get(b).__currentAnisotropy=b.anisotropy)}function B(a,b){if(a.width>b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a}function y(a){return [...]
+THREE.Math.isPowerOfTwo(a.height)}function z(a,b){var c=W.get(a);if(6===a.image.length)if(0<a.version&&c.__version!==a.version){c.__image__webglTextureCube||(a.addEventListener("dispose",g),c.__image__webglTextureCube=r.createTexture(),la.textures++);I.activeTexture(r.TEXTURE0+b);I.bindTexture(r.TEXTURE_CUBE_MAP,c.__image__webglTextureCube);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,a.flipY);for(var d=a instanceof THREE.CompressedTexture,e=a.image[0]instanceof THREE.DataTexture,f=[],h=0;6>h;h++ [...]
+d||e?e?a.image[h].image:a.image[h]:B(a.image[h],ha.maxCubemapSize);var k=y(f[0]),l=N(a.format),n=N(a.type);x(r.TEXTURE_CUBE_MAP,a,k);for(h=0;6>h;h++)if(d)for(var m,q=f[h].mipmaps,p=0,s=q.length;p<s;p++)m=q[p],a.format!==THREE.RGBAFormat&&a.format!==THREE.RGBFormat?-1<I.getCompressedTextureFormats().indexOf(l)?I.compressedTexImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+h,p,l,m.width,m.height,0,m.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .se [...]
+I.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+h,p,l,m.width,m.height,0,l,n,m.data);else e?I.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+h,0,l,f[h].width,f[h].height,0,l,n,f[h].data):I.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+h,0,l,l,n,f[h]);a.generateMipmaps&&k&&r.generateMipmap(r.TEXTURE_CUBE_MAP);c.__version=a.version;if(a.onUpdate)a.onUpdate(a)}else I.activeTexture(r.TEXTURE0+b),I.bindTexture(r.TEXTURE_CUBE_MAP,c.__image__webglTextureCube)}function A(a,b){I.activeTexture(r.TEXTURE0+b);I.bin [...]
+W.get(a).__webglTexture)}function J(a,b,c){r.bindFramebuffer(r.FRAMEBUFFER,a);r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,c,W.get(b.texture).__webglTexture,0)}function F(a,b){r.bindRenderbuffer(r.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_COMPONENT16,b.width,b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STEN [...]
+b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,a)):r.renderbufferStorage(r.RENDERBUFFER,r.RGBA4,b.width,b.height)}function C(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?r.NEAREST:r.LINEAR}function N(a){var b;if(a===THREE.RepeatWrapping)return r.REPEAT;if(a===THREE.ClampToEdgeWrapping)return r.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return r.MIRRORED_REPEAT;if(a===THREE. [...]
+if(a===THREE.NearestMipMapNearestFilter)return r.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return r.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return r.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return r.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return r.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return r.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return r.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return r.UNSIGN [...]
+if(a===THREE.UnsignedShort565Type)return r.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return r.BYTE;if(a===THREE.ShortType)return r.SHORT;if(a===THREE.UnsignedShortType)return r.UNSIGNED_SHORT;if(a===THREE.IntType)return r.INT;if(a===THREE.UnsignedIntType)return r.UNSIGNED_INT;if(a===THREE.FloatType)return r.FLOAT;b=S.get("OES_texture_half_float");if(null!==b&&a===THREE.HalfFloatType)return b.HALF_FLOAT_OES;if(a===THREE.AlphaFormat)return r.ALPHA;if(a===THREE.RGBFormat)return r.RGB;if(a= [...]
+if(a===THREE.LuminanceFormat)return r.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return r.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return r.FUNC_ADD;if(a===THREE.SubtractEquation)return r.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return r.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return r.ZERO;if(a===THREE.OneFactor)return r.ONE;if(a===THREE.SrcColorFactor)return r.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return r.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return  [...]
+if(a===THREE.OneMinusSrcAlphaFactor)return r.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return r.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return r.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return r.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return r.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return r.SRC_ALPHA_SATURATE;b=S.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE. [...]
+if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=S.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRE [...]
+S.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var L=void 0!==a.canvas?a.canvas:document.createElement("canvas"),Q=void 0!==a.context?a.context:null,M=L.width,K=L.height,E=1,O=void 0!==a.alpha?a.alpha:!1,T=void 0!==a.depth?a.depth:!0,H=void 0!==a.stencil?a.stencil:!0,R=void 0!==a.antialias?a.antialias:!1,G=void 0!==a.premultipliedAlpha?a.premultip [...]
+!0,ia=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,U=new THREE.Color(0),X=0,da=[],ca=[],ga=-1,Z=[],fa=-1,ma=new Float32Array(8),ea=[],ja=[];this.domElement=L;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.gammaFactor=2;this.gammaOutput=this.gammaInput=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;var aa=this,Aa=null,za=null,ta=-1,sa="",ra=null,ya=0,na=0,oa=0,pa=L.width,qa= [...]
+Da=0,Ea=0,Ba=new THREE.Frustum,xa=new THREE.Matrix4,V=new THREE.Vector3,Y=new THREE.Vector3,wa=!0,Ca={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[],decays:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[],decays:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},la={geometries:0,textures:0},ka={calls:0,vertices:0,faces:0,points:0};this.info={render:ka,memory:la,pro [...]
+var r;try{O={alpha:O,depth:T,stencil:H,antialias:R,premultipliedAlpha:G,preserveDrawingBuffer:ia};r=Q||L.getContext("webgl",O)||L.getContext("experimental-webgl",O);if(null===r){if(null!==L.getContext("webgl"))throw"Error creating WebGL context with your selected attributes.";throw"Error creating WebGL context.";}L.addEventListener("webglcontextlost",e,!1)}catch(Fa){console.error("THREE.WebGLRenderer: "+Fa)}var S=new THREE.WebGLExtensions(r);S.get("OES_texture_float");S.get("OES_texture_ [...]
+S.get("OES_texture_half_float");S.get("OES_texture_half_float_linear");S.get("OES_standard_derivatives");S.get("ANGLE_instanced_arrays");S.get("OES_element_index_uint")&&(THREE.BufferGeometry.MaxIndex=4294967296);var ha=new THREE.WebGLCapabilities(r,S,a),I=new THREE.WebGLState(r,S,N),W=new THREE.WebGLProperties,va=new THREE.WebGLObjects(r,W,this.info),ua=new THREE.WebGLPrograms(this,ha);this.info.programs=ua.programs;var Ga=new THREE.WebGLBufferRenderer(r,S,ka),Ha=new THREE.WebGLIndexedB [...]
+S,ka);c();this.context=r;this.capabilities=ha;this.extensions=S;this.state=I;var $=new THREE.WebGLShadowMap(this,da,va);this.shadowMap=$;var Ia=new THREE.SpritePlugin(this,ea),Ja=new THREE.LensFlarePlugin(this,ja);this.getContext=function(){return r};this.getContextAttributes=function(){return r.getContextAttributes()};this.forceContextLoss=function(){S.get("WEBGL_lose_context").loseContext()};this.getMaxAnisotropy=function(){var a;return function(){if(void 0!==a)return a;var b=S.get("EX [...]
+return a=null!==b?r.getParameter(b.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0}}();this.getPrecision=function(){return ha.precision};this.getPixelRatio=function(){return E};this.setPixelRatio=function(a){void 0!==a&&(E=a)};this.getSize=function(){return{width:M,height:K}};this.setSize=function(a,b,c){M=a;K=b;L.width=a*E;L.height=b*E;!1!==c&&(L.style.width=a+"px",L.style.height=b+"px");this.setViewport(0,0,a,b)};this.setViewport=function(a,b,c,d){na=a*E;oa=b*E;pa=c*E;qa=d*E;r.viewport(na,oa,pa,qa)} [...]
+function(a){a.x=na/E;a.y=oa/E;a.z=pa/E;a.w=qa/E};this.setScissor=function(a,b,c,d){r.scissor(a*E,b*E,c*E,d*E)};this.enableScissorTest=function(a){I.setScissorTest(a)};this.getClearColor=function(){return U};this.setClearColor=function(a,c){U.set(a);X=void 0!==c?c:1;b(U.r,U.g,U.b,X)};this.getClearAlpha=function(){return X};this.setClearAlpha=function(a){X=a;b(U.r,U.g,U.b,X)};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=r.COLOR_BUFFER_BIT;if(void 0===b||b)d|=r.DEPTH_BUFFER_BIT;if [...]
+c||c)d|=r.STENCIL_BUFFER_BIT;r.clear(d)};this.clearColor=function(){r.clear(r.COLOR_BUFFER_BIT)};this.clearDepth=function(){r.clear(r.DEPTH_BUFFER_BIT)};this.clearStencil=function(){r.clear(r.STENCIL_BUFFER_BIT)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.resetGLState=d;this.dispose=function(){L.removeEventListener("webglcontextlost",e,!1)};this.renderBufferImmediate=function(a,b,c){I.initAttributes();var d=W.get(a);a.hasPositions&&!d.position&&(d. [...]
+r.createBuffer());a.hasNormals&&!d.normal&&(d.normal=r.createBuffer());a.hasUvs&&!d.uv&&(d.uv=r.createBuffer());a.hasColors&&!d.color&&(d.color=r.createBuffer());b=b.getAttributes();a.hasPositions&&(r.bindBuffer(r.ARRAY_BUFFER,d.position),r.bufferData(r.ARRAY_BUFFER,a.positionArray,r.DYNAMIC_DRAW),I.enableAttribute(b.position),r.vertexAttribPointer(b.position,3,r.FLOAT,!1,0,0));if(a.hasNormals){r.bindBuffer(r.ARRAY_BUFFER,d.normal);if("MeshPhongMaterial"!==c.type&&c.shading===THREE.FlatS [...]
+0,f=3*a.count;e<f;e+=9){var g=a.normalArray,h=(g[e+0]+g[e+3]+g[e+6])/3,k=(g[e+1]+g[e+4]+g[e+7])/3,l=(g[e+2]+g[e+5]+g[e+8])/3;g[e+0]=h;g[e+1]=k;g[e+2]=l;g[e+3]=h;g[e+4]=k;g[e+5]=l;g[e+6]=h;g[e+7]=k;g[e+8]=l}r.bufferData(r.ARRAY_BUFFER,a.normalArray,r.DYNAMIC_DRAW);I.enableAttribute(b.normal);r.vertexAttribPointer(b.normal,3,r.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(r.bindBuffer(r.ARRAY_BUFFER,d.uv),r.bufferData(r.ARRAY_BUFFER,a.uvArray,r.DYNAMIC_DRAW),I.enableAttribute(b.uv),r.vertexAttribPointer [...]
+!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(r.bindBuffer(r.ARRAY_BUFFER,d.color),r.bufferData(r.ARRAY_BUFFER,a.colorArray,r.DYNAMIC_DRAW),I.enableAttribute(b.color),r.vertexAttribPointer(b.color,3,r.FLOAT,!1,0,0));I.disableUnusedAttributes();r.drawArrays(r.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,e,f,g){t(e);var h=v(a,b,c,e,f),l=!1;a=d.id+"_"+h.id+"_"+e.wireframe;a!==sa&&(sa=a,l=!0);b=f.morphTargetInfluences;if(void 0!==b){a=[];c=0;for(l=b.leng [...]
+b[c];a.push([n,c])}a.sort(k);8<a.length&&(a.length=8);var m=d.morphAttributes;c=0;for(l=a.length;c<l;c++)n=a[c],ma[c]=n[0],0!==n[0]?(b=n[1],!0===e.morphTargets&&m.position&&d.addAttribute("morphTarget"+c,m.position[b]),!0===e.morphNormals&&m.normal&&d.addAttribute("morphNormal"+c,m.normal[b])):(!0===e.morphTargets&&d.removeAttribute("morphTarget"+c),!0===e.morphNormals&&d.removeAttribute("morphNormal"+c));a=h.getUniforms();null!==a.morphTargetInfluences&&r.uniform1fv(a.morphTargetInfluen [...]
+!0}b=d.index;c=d.attributes.position;!0===e.wireframe&&(b=va.getWireframeAttribute(d));null!==b?(a=Ha,a.setIndex(b)):a=Ga;if(l){a:{var l=void 0,q;if(d instanceof THREE.InstancedBufferGeometry&&(q=S.get("ANGLE_instanced_arrays"),null===q)){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");break a}void 0===l&&(l=0);I.initAttributes();var n=d.attributes,h=h.getAttributes(),m=e.defau [...]
+p;for(p in h){var s=h[p];if(0<=s){var u=n[p];if(void 0!==u){var w=u.itemSize,x=va.getAttributeBuffer(u);if(u instanceof THREE.InterleavedBufferAttribute){var F=u.data,D=F.stride,u=u.offset;F instanceof THREE.InstancedInterleavedBuffer?(I.enableAttributeAndDivisor(s,F.meshPerAttribute,q),void 0===d.maxInstancedCount&&(d.maxInstancedCount=F.meshPerAttribute*F.count)):I.enableAttribute(s);r.bindBuffer(r.ARRAY_BUFFER,x);r.vertexAttribPointer(s,w,r.FLOAT,!1,D*F.array.BYTES_PER_ELEMENT,(l*D+u) [...]
+THREE.InstancedBufferAttribute?(I.enableAttributeAndDivisor(s,u.meshPerAttribute,q),void 0===d.maxInstancedCount&&(d.maxInstancedCount=u.meshPerAttribute*u.count)):I.enableAttribute(s),r.bindBuffer(r.ARRAY_BUFFER,x),r.vertexAttribPointer(s,w,r.FLOAT,!1,0,l*w*4)}else if(void 0!==m&&(w=m[p],void 0!==w))switch(w.length){case 2:r.vertexAttrib2fv(s,w);break;case 3:r.vertexAttrib3fv(s,w);break;case 4:r.vertexAttrib4fv(s,w);break;default:r.vertexAttrib1fv(s,w)}}}I.disableUnusedAttributes()}null [...]
+va.getAttributeBuffer(b))}q=Infinity;null!==b?q=b.count:void 0!==c&&(q=c.count);p=d.drawRange.start;b=d.drawRange.count;c=null!==g?g.start:0;l=null!==g?g.count:Infinity;g=Math.max(0,p,c);q=Math.min(0+q,p+b,c+l)-1;q=Math.max(0,q-g+1);f instanceof THREE.Mesh?(!0===e.wireframe?(I.setLineWidth(e.wireframeLinewidth*E),a.setMode(r.LINES)):a.setMode(r.TRIANGLES),d instanceof THREE.InstancedBufferGeometry&&0<d.maxInstancedCount?a.renderInstances(d):a.render(g,q)):f instanceof THREE.Line?(d=e.lin [...]
+d&&(d=1),I.setLineWidth(d*E),f instanceof THREE.LineSegments?a.setMode(r.LINES):a.setMode(r.LINE_STRIP),a.render(g,q)):f instanceof THREE.Points&&(a.setMode(r.POINTS),a.render(g,q))};this.render=function(a,b,c,d){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var e=a.fog;sa="";ta=-1;ra=null;wa=!0;!0===a.autoUpdate&&a.updateMatrixWorld();null===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b. [...]
+xa.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);Ba.setFromMatrix(xa);da.length=0;fa=ga=-1;ea.length=0;ja.length=0;q(a,b);ca.length=ga+1;Z.length=fa+1;!0===aa.sortObjects&&(ca.sort(m),Z.sort(p));$.render(a);ka.calls=0;ka.vertices=0;ka.faces=0;ka.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);a.overrideMaterial?(d=a.overrideMaterial,s(ca,b,da,e,d),s(Z,b,da,e,d)):(I.setBlending(THREE.NoBlending),s( [...]
+s(Z,b,da,e));Ia.render(a,b);Ja.render(a,b,Da,Ea);c&&(a=c.texture,b=y(c),a.generateMipmaps&&b&&a.minFilter!==THREE.NearestFilter&&a.minFilter!==THREE.LinearFilter&&(a=c instanceof THREE.WebGLRenderTargetCube?r.TEXTURE_CUBE_MAP:r.TEXTURE_2D,c=W.get(c.texture).__webglTexture,I.bindTexture(a,c),r.generateMipmap(a),I.bindTexture(a,null)));I.setDepthTest(!0);I.setDepthWrite(!0);I.setColorWrite(!0)}};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?I.disable(r.CULL_FACE):(b===THREE.Fron [...]
+r.frontFace(r.CW):r.frontFace(r.CCW),a===THREE.CullFaceBack?r.cullFace(r.BACK):a===THREE.CullFaceFront?r.cullFace(r.FRONT):r.cullFace(r.FRONT_AND_BACK),I.enable(r.CULL_FACE))};this.setTexture=function(a,b){var c=W.get(a);if(0<a.version&&c.__version!==a.version){var d=a.image;if(void 0===d)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined",a);else if(!1===d.complete)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete",a);e [...]
+c.__webglInit&&(c.__webglInit=!0,a.addEventListener("dispose",g),c.__webglTexture=r.createTexture(),la.textures++);I.activeTexture(r.TEXTURE0+b);I.bindTexture(r.TEXTURE_2D,c.__webglTexture);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,a.flipY);r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha);r.pixelStorei(r.UNPACK_ALIGNMENT,a.unpackAlignment);a.image=B(a.image,ha.maxTextureSize);if((a.wrapS!==THREE.ClampToEdgeWrapping||a.wrapT!==THREE.ClampToEdgeWrapping||a.minFilter!==THREE.Nea [...]
+a.minFilter!==THREE.LinearFilter)&&!1===y(a.image)){d=a.image;if(d instanceof HTMLImageElement||d instanceof HTMLCanvasElement){var e=document.createElement("canvas");e.width=THREE.Math.nearestPowerOfTwo(d.width);e.height=THREE.Math.nearestPowerOfTwo(d.height);e.getContext("2d").drawImage(d,0,0,e.width,e.height);console.warn("THREE.WebGLRenderer: image is not power of two ("+d.width+"x"+d.height+"). Resized to "+e.width+"x"+e.height,d);d=e}a.image=d}var f=a.image,d=y(f),e=N(a.format),h=N [...]
+x(r.TEXTURE_2D,a,d);var k=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<k.length&&d){for(var l=0,n=k.length;l<n;l++)f=k[l],I.texImage2D(r.TEXTURE_2D,l,e,f.width,f.height,0,e,h,f.data);a.generateMipmaps=!1}else I.texImage2D(r.TEXTURE_2D,0,e,f.width,f.height,0,e,h,f.data);else if(a instanceof THREE.CompressedTexture)for(l=0,n=k.length;l<n;l++)f=k[l],a.format!==THREE.RGBAFormat&&a.format!==THREE.RGBFormat?-1<I.getCompressedTextureFormats().indexOf(e)?I.compressedTexImage2D(r.TEXTURE_2D,l [...]
+f.height,0,f.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):I.texImage2D(r.TEXTURE_2D,l,e,f.width,f.height,0,e,h,f.data);else if(0<k.length&&d){l=0;for(n=k.length;l<n;l++)f=k[l],I.texImage2D(r.TEXTURE_2D,l,e,e,h,f);a.generateMipmaps=!1}else I.texImage2D(r.TEXTURE_2D,0,e,e,h,a.image);a.generateMipmaps&&d&&r.generateMipmap(r.TEXTURE_2D);c.__version=a.version;if(a.onUpdate)a.onUpdate(a)}}else I.activeTexture(r.TEXTURE0+b) [...]
+c.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&void 0===W.get(a).__webglFramebuffer){var c=W.get(a),d=W.get(a.texture);void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",f);d.__webglTexture=r.createTexture();la.textures++;var e=y(a),g=N(a.texture.format),h=N(a.texture.type);if(b){c.__webglFramebuffer=[];c.__webglRenderbuffer=[];I.bindTexture(r.TEXTURE_CUBE_MAP,d._ [...]
+x(r.TEXTURE_CUBE_MAP,a.texture,e);for(d=0;6>d;d++)c.__webglFramebuffer[d]=r.createFramebuffer(),c.__webglRenderbuffer[d]=r.createRenderbuffer(),I.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+d,0,g,a.width,a.height,0,g,h,null),J(c.__webglFramebuffer[d],a,r.TEXTURE_CUBE_MAP_POSITIVE_X+d),F(c.__webglRenderbuffer[d],a);a.texture.generateMipmaps&&e&&r.generateMipmap(r.TEXTURE_CUBE_MAP)}else c.__webglFramebuffer=r.createFramebuffer(),c.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglR [...]
+r.createRenderbuffer(),I.bindTexture(r.TEXTURE_2D,d.__webglTexture),x(r.TEXTURE_2D,a.texture,e),I.texImage2D(r.TEXTURE_2D,0,g,a.width,a.height,0,g,h,null),J(c.__webglFramebuffer,a,r.TEXTURE_2D),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,c.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,c.__webglRenderbuffer):F(c.__webglRend [...]
+a),a.texture.generateMipmaps&&e&&r.generateMipmap(r.TEXTURE_2D);b?I.bindTexture(r.TEXTURE_CUBE_MAP,null):I.bindTexture(r.TEXTURE_2D,null);r.bindRenderbuffer(r.RENDERBUFFER,null);r.bindFramebuffer(r.FRAMEBUFFER,null)}a?(c=W.get(a),d=b?c.__webglFramebuffer[a.activeCubeFace]:c.__webglFramebuffer,c=a.width,e=a.height,h=g=0):(d=null,c=pa,e=qa,g=na,h=oa);d!==za&&(r.bindFramebuffer(r.FRAMEBUFFER,d),r.viewport(g,h,c,e),za=d);b&&(d=W.get(a.texture),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATT [...]
+r.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,d.__webglTexture,0));Da=c;Ea=e};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!1===a instanceof THREE.WebGLRenderTarget)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else{var g=W.get(a).__webglFramebuffer;if(g){var h=!1;g!==za&&(r.bindFramebuffer(r.FRAMEBUFFER,g),h=!0);try{var k=a.texture;k.format!==THREE.RGBAFormat&&N(k.format)!==r.getParameter(r.IMPLEMENTATION_COLOR_READ_FO [...]
+k.type===THREE.UnsignedByteType||N(k.type)===r.getParameter(r.IMPLEMENTATION_COLOR_READ_TYPE)||k.type===THREE.FloatType&&S.get("WEBGL_color_buffer_float")||k.type===THREE.HalfFloatType&&S.get("EXT_color_buffer_half_float")?r.checkFramebufferStatus(r.FRAMEBUFFER)===r.FRAMEBUFFER_COMPLETE?r.readPixels(b,c,d,e,N(k.format),N(k.type),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer [...]
+r.bindFramebuffer(r.FRAMEBUFFER,za)}}}};this.supportsFloatTextures=function(){console.warn("THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( 'OES_texture_float' ).");return S.get("OES_texture_float")};this.supportsHalfFloatTextures=function(){console.warn("THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( 'OES_texture_half_float' ).");return S.get("OES_texture_half_float")};this.supportsStandardDerivatives=function(){console.warn("THREE.WebGLR [...]
+return S.get("OES_standard_derivatives")};this.supportsCompressedTextureS3TC=function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( 'WEBGL_compressed_texture_s3tc' ).");return S.get("WEBGL_compressed_texture_s3tc")};this.supportsCompressedTexturePVRTC=function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( 'WEBGL_compressed_texture_pvrtc' ).");return S.get("WEBGL_compressed_texture_pvrtc")};th [...]
+function(){console.warn("THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( 'EXT_blend_minmax' ).");return S.get("EXT_blend_minmax")};this.supportsVertexTextures=function(){return ha.vertexTextures};this.supportsInstancedArrays=function(){console.warn("THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( 'ANGLE_instanced_arrays' ).");return S.get("ANGLE_instanced_arrays")};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial()  [...]
+this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")};Object.defineProperties(this,{shadowMapEnabled:{get:function(){return $.enabled},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.");$. [...]
+shadowMapType:{get:function(){return $.type},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.");$.type=a}},shadowMapCullFace:{get:function(){return $.cullFace},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.");$.cullFace=a}},shadowMapDebug:{get:function(){return $.debug},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.");$.debug=a}}})};
+THREE.WebGLRenderTarget=function(a,b,c){this.uuid=THREE.Math.generateUUID();this.width=a;this.height=b;c=c||{};void 0===c.minFilter&&(c.minFilter=THREE.LinearFilter);this.texture=new THREE.Texture(void 0,void 0,c.wrapS,c.wrapT,c.magFilter,c.minFilter,c.format,c.type,c.anisotropy);this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.shareDepthFrom=void 0!==c.shareDepthFrom?c.shareDepthFrom:null};
+THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,get wrapS(){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.");return this.texture.wrapS},set wrapS(a){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.");this.texture.wrapS=a},get wrapT(){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");return this.texture.wrapT},set wrapT(a){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");this.textur [...]
+get magFilter(){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.");return this.texture.magFilter},set magFilter(a){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.");this.texture.magFilter=a},get minFilter(){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");return this.texture.minFilter},set minFilter(a){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");this.texture.minFilter [...]
+return this.texture.anisotropy},set anisotropy(a){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.");this.texture.anisotropy=a},get offset(){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");return this.texture.offset},set offset(a){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");this.texture.offset=a},get repeat(){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat.");return this.texture.repe [...]
+this.texture.repeat=a},get format(){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format.");return this.texture.format},set format(a){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format.");this.texture.format=a},get type(){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type.");return this.texture.type},set type(a){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type.");this.texture.type=a},get generateMipmaps(){console.warn("T [...]
+return this.texture.generateMipmaps},set generateMipmaps(a){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.");this.texture.generateMipmaps=a},setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose()},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.texture=a.texture.clone();this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuff [...]
+a.shareDepthFrom;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube;
+THREE.WebGLBufferRenderer=function(a,b,c){var d;this.setMode=function(a){d=a};this.render=function(b,g){a.drawArrays(d,b,g);c.calls++;c.vertices+=g;d===a.TRIANGLES&&(c.faces+=g/3)};this.renderInstances=function(a){var c=b.get("ANGLE_instanced_arrays");if(null===c)console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");else{var f=a.attributes.position;f instanceof THREE.InterleavedBufferAttribute?c.dra [...]
+0,f.data.count,a.maxInstancedCount):c.drawArraysInstancedANGLE(d,0,f.count,a.maxInstancedCount)}}};
+THREE.WebGLIndexedBufferRenderer=function(a,b,c){var d,e,g;this.setMode=function(a){d=a};this.setIndex=function(c){c.array instanceof Uint32Array&&b.get("OES_element_index_uint")?(e=a.UNSIGNED_INT,g=4):(e=a.UNSIGNED_SHORT,g=2)};this.render=function(b,h){a.drawElements(d,h,e,b*g);c.calls++;c.vertices+=h;d===a.TRIANGLES&&(c.faces+=h/3)};this.renderInstances=function(a){var c=b.get("ANGLE_instanced_arrays");null===c?console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeomet [...]
+c.drawElementsInstancedANGLE(d,a.index.array.length,e,0,a.maxInstancedCount)}};
+THREE.WebGLExtensions=function(a){var b={};this.get=function(c){if(void 0!==b[c])return b[c];var d;switch(c){case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case "WEBGL_compressed_texture_s3tc":d=a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compres [...]
+break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;default:d=a.getExtension(c)}null===d&&console.warn("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}};
+THREE.WebGLCapabilities=function(a,b,c){function d(b){if("highp"===b){if(0<a.getShaderPrecisionFormat(a.VERTEX_SHADER,a.HIGH_FLOAT).precision&&0<a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.HIGH_FLOAT).precision)return"highp";b="mediump"}return"mediump"===b&&0<a.getShaderPrecisionFormat(a.VERTEX_SHADER,a.MEDIUM_FLOAT).precision&&0<a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.MEDIUM_FLOAT).precision?"mediump":"lowp"}this.getMaxPrecision=d;this.precision=void 0!==c.precision?c.precisio [...]
+this.logarithmicDepthBuffer=void 0!==c.logarithmicDepthBuffer?c.logarithmicDepthBuffer:!1;this.maxTextures=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS);this.maxVertexTextures=a.getParameter(a.MAX_VERTEX_TEXTURE_IMAGE_UNITS);this.maxTextureSize=a.getParameter(a.MAX_TEXTURE_SIZE);this.maxCubemapSize=a.getParameter(a.MAX_CUBE_MAP_TEXTURE_SIZE);this.maxAttributes=a.getParameter(a.MAX_VERTEX_ATTRIBS);this.maxVertexUniforms=a.getParameter(a.MAX_VERTEX_UNIFORM_VECTORS);this.maxVaryings=a.getParame [...]
+this.maxFragmentUniforms=a.getParameter(a.MAX_FRAGMENT_UNIFORM_VECTORS);this.vertexTextures=0<this.maxVertexTextures;this.floatFragmentTextures=!!b.get("OES_texture_float");this.floatVertexTextures=this.vertexTextures&&this.floatFragmentTextures;c=d(this.precision);c!==this.precision&&(console.warn("THREE.WebGLRenderer:",this.precision,"not supported, using",c,"instead."),this.precision=c);this.logarithmicDepthBuffer&&(this.logarithmicDepthBuffer=!!b.get("EXT_frag_depth"))};
+THREE.WebGLGeometries=function(a,b,c){function d(a){a=a.target;var h=g[a.id].attributes,l;for(l in h)e(h[l]);a.removeEventListener("dispose",d);delete g[a.id];l=b.get(a);l.wireframe&&e(l.wireframe);c.memory.geometries--}function e(c){var d;d=c instanceof THREE.InterleavedBufferAttribute?b.get(c.data).__webglBuffer:b.get(c).__webglBuffer;void 0!==d&&(a.deleteBuffer(d),c instanceof THREE.InterleavedBufferAttribute?b.delete(c.data):b.delete(c))}var g={};this.get=function(a){var b=a.geometry [...]
+g[b.id])return g[b.id];b.addEventListener("dispose",d);var e;b instanceof THREE.BufferGeometry?e=b:b instanceof THREE.Geometry&&(void 0===b._bufferGeometry&&(b._bufferGeometry=(new THREE.BufferGeometry).setFromObject(a)),e=b._bufferGeometry);g[b.id]=e;c.memory.geometries++;return e}};
+THREE.WebGLObjects=function(a,b,c){function d(c,d){var e=c instanceof THREE.InterleavedBufferAttribute?c.data:c,g=b.get(e);void 0===g.__webglBuffer?(g.__webglBuffer=a.createBuffer(),a.bindBuffer(d,g.__webglBuffer),a.bufferData(d,e.array,e.dynamic?a.DYNAMIC_DRAW:a.STATIC_DRAW),g.version=e.version):g.version!==e.version&&(a.bindBuffer(d,g.__webglBuffer),!1===e.dynamic||-1===e.updateRange.count?a.bufferSubData(d,0,e.array):0===e.updateRange.count?console.error("THREE.WebGLObjects.updateBuff [...]
+(a.bufferSubData(d,e.updateRange.offset*e.array.BYTES_PER_ELEMENT,e.array.subarray(e.updateRange.offset,e.updateRange.offset+e.updateRange.count)),e.updateRange.count=0),g.version=e.version)}function e(a,b,c){if(b>c){var d=b;b=c;c=d}d=a[b];return void 0===d?(a[b]=[c],!0):-1===d.indexOf(c)?(d.push(c),!0):!1}var g=new THREE.WebGLGeometries(a,b,c);this.getAttributeBuffer=function(a){return a instanceof THREE.InterleavedBufferAttribute?b.get(a.data).__webglBuffer:b.get(a).__webglBuffer};this [...]
+function(c){var g=b.get(c);if(void 0!==g.wireframe)return g.wireframe;var l=[],k=c.index,m=c.attributes;c=m.position;if(null!==k)for(var m={},k=k.array,p=0,n=k.length;p<n;p+=3){var q=k[p+0],s=k[p+1],t=k[p+2];e(m,q,s)&&l.push(q,s);e(m,s,t)&&l.push(s,t);e(m,t,q)&&l.push(t,q)}else for(k=m.position.array,p=0,n=k.length/3-1;p<n;p+=3)q=p+0,s=p+1,t=p+2,l.push(q,s,s,t,t,q);l=new THREE.BufferAttribute(new (65535<c.count?Uint32Array:Uint16Array)(l),1);d(l,a.ELEMENT_ARRAY_BUFFER);return g.wireframe [...]
+function(b){var c=g.get(b);b.geometry instanceof THREE.Geometry&&c.updateFromObject(b);b=c.index;var e=c.attributes;null!==b&&d(b,a.ELEMENT_ARRAY_BUFFER);for(var k in e)d(e[k],a.ARRAY_BUFFER);b=c.morphAttributes;for(k in b)for(var e=b[k],m=0,p=e.length;m<p;m++)d(e[m],a.ARRAY_BUFFER);return c}};
+THREE.WebGLProgram=function(){function a(a){var b=[],c;for(c in a){var f=a[c];!1!==f&&b.push("#define "+c+" "+f)}return b.join("\n")}function b(a){return""!==a}var c=0;return function(d,e,g,f){var h=d.context,l=g.defines,k=g.__webglShader.vertexShader,m=g.__webglShader.fragmentShader,p="SHADOWMAP_TYPE_BASIC";f.shadowMapType===THREE.PCFShadowMap?p="SHADOWMAP_TYPE_PCF":f.shadowMapType===THREE.PCFSoftShadowMap&&(p="SHADOWMAP_TYPE_PCF_SOFT");var n="ENVMAP_TYPE_CUBE",q="ENVMAP_MODE_REFLECTION [...]
+if(f.envMap){switch(g.envMap.mapping){case THREE.CubeReflectionMapping:case THREE.CubeRefractionMapping:n="ENVMAP_TYPE_CUBE";break;case THREE.EquirectangularReflectionMapping:case THREE.EquirectangularRefractionMapping:n="ENVMAP_TYPE_EQUIREC";break;case THREE.SphericalReflectionMapping:n="ENVMAP_TYPE_SPHERE"}switch(g.envMap.mapping){case THREE.CubeRefractionMapping:case THREE.EquirectangularRefractionMapping:q="ENVMAP_MODE_REFRACTION"}switch(g.combine){case THREE.MultiplyOperation:s="ENV [...]
+break;case THREE.MixOperation:s="ENVMAP_BLENDING_MIX";break;case THREE.AddOperation:s="ENVMAP_BLENDING_ADD"}}var t=0<d.gammaFactor?d.gammaFactor:1,v=a(l),u=h.createProgram();g instanceof THREE.RawShaderMaterial?d=l="":(l=["precision "+f.precision+" float;","precision "+f.precision+" int;","#define SHADER_NAME "+g.__webglShader.name,v,f.supportsVertexTextures?"#define VERTEX_TEXTURES":"",d.gammaInput?"#define GAMMA_INPUT":"",d.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+ [...]
+f.maxDirLights,"#define MAX_POINT_LIGHTS "+f.maxPointLights,"#define MAX_SPOT_LIGHTS "+f.maxSpotLights,"#define MAX_HEMI_LIGHTS "+f.maxHemiLights,"#define MAX_SHADOWS "+f.maxShadows,"#define MAX_BONES "+f.maxBones,f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+q:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.emissiveMap?"#define USE_EMISSIVEMAP":"",f.bumpMap?"#define USE_BUMPMAP":"",f.normalMap?"#define USE_NORMALMAP":"",f.displa [...]
+f.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",f.specularMap?"#define USE_SPECULARMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",f.flatShading?"#define FLAT_SHADED":"",f.skinning?"#define USE_SKINNING":"",f.useVertexTexture?"#define BONE_TEXTURE":"",f.morphTargets?"#define USE_MORPHTARGETS":"",f.morphNormals&&!1===f.flatShading?"#define USE_MORPHNORMALS":"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowM [...]
+"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+p:"",f.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",0<f.pointLightShadows?"#define POINT_LIGHT_SHADOWS":"",f.sizeAttenuation?"#define USE_SIZEATTENUATION":"",f.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&d.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform m [...]
+"uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else [...]
+"\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(b).join("\n"),d=[f.bumpMap||f.normalMap||f.flatShading||g.derivatives?"#extension GL_OES_standard_derivatives : enable":"",f.logarithmicDepthBuffer&&d.extensions.get("EXT_frag_depth")?"#extension GL_EXT_frag_depth : enable":"","precision "+f.precision+" float;", [...]
+f.precision+" int;","#define SHADER_NAME "+g.__webglShader.name,v,"#define MAX_DIR_LIGHTS "+f.maxDirLights,"#define MAX_POINT_LIGHTS "+f.maxPointLights,"#define MAX_SPOT_LIGHTS "+f.maxSpotLights,"#define MAX_HEMI_LIGHTS "+f.maxHemiLights,"#define MAX_SHADOWS "+f.maxShadows,f.alphaTest?"#define ALPHATEST "+f.alphaTest:"",d.gammaInput?"#define GAMMA_INPUT":"",d.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+t,f.useFog&&f.fog?"#define USE_FOG":"",f.useFog&&f.fogExp?"#define F [...]
+"",f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+n:"",f.envMap?"#define "+q:"",f.envMap?"#define "+s:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.emissiveMap?"#define USE_EMISSIVEMAP":"",f.bumpMap?"#define USE_BUMPMAP":"",f.normalMap?"#define USE_NORMALMAP":"",f.specularMap?"#define USE_SPECULARMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",f.flatShading?"#define FLAT_SHADED":"",f.metal?"#de [...]
+"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowMapEnabled?"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+p:"",f.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",0<f.pointLightShadows?"#define POINT_LIGHT_SHADOWS":"",f.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&d.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","\n"].filter(b).join("\n" [...]
+k=THREE.WebGLShader(h,h.VERTEX_SHADER,l+k);m=THREE.WebGLShader(h,h.FRAGMENT_SHADER,m);h.attachShader(u,k);h.attachShader(u,m);void 0!==g.index0AttributeName?h.bindAttribLocation(u,0,g.index0AttributeName):!0===f.morphTargets&&h.bindAttribLocation(u,0,"position");h.linkProgram(u);f=h.getProgramInfoLog(u);p=h.getShaderInfoLog(k);n=h.getShaderInfoLog(m);s=q=!0;if(!1===h.getProgramParameter(u,h.LINK_STATUS))q=!1,console.error("THREE.WebGLProgram: shader error: ",h.getError(),"gl.VALIDATE_STA [...]
+h.VALIDATE_STATUS),"gl.getProgramInfoLog",f,p,n);else if(""!==f)console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",f);else if(""===p||""===n)s=!1;s&&(this.diagnostics={runnable:q,material:g,programLog:f,vertexShader:{log:p,prefix:l},fragmentShader:{log:n,prefix:d}});h.deleteShader(k);h.deleteShader(m);var w;this.getUniforms=function(){if(void 0===w){for(var a={},b=h.getProgramParameter(u,h.ACTIVE_UNIFORMS),c=0;c<b;c++){var d=h.getActiveUniform(u,c).name,e=h.getUniformLocation(u,d) [...]
+-1!==f&&f===d.length-3&&(a[d.substr(0,f)]=e);a[d]=e}w=a}return w};var D;this.getAttributes=function(){if(void 0===D){for(var a={},b=h.getProgramParameter(u,h.ACTIVE_ATTRIBUTES),c=0;c<b;c++){var d=h.getActiveAttrib(u,c).name;a[d]=h.getAttribLocation(u,d)}D=a}return D};this.destroy=function(){h.deleteProgram(u);this.program=void 0};Object.defineProperties(this,{uniforms:{get:function(){console.warn("THREE.WebGLProgram: .uniforms is now .getUniforms().");return this.getUniforms()}},attribut [...]
+return this.getAttributes()}}});this.id=c++;this.code=e;this.usedTimes=1;this.program=u;this.vertexShader=k;this.fragmentShader=m;return this}}();
+THREE.WebGLPrograms=function(a,b){var c=[],d={MeshDepthMaterial:"depth",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points"},e="precision supportsVertexTextures map envMap envMapMode lightMap aoMap emissiveMap bumpMap normalMap displacementMap specularMap alphaMap combine vertexColors fog useFog fogExp flatShading sizeAttenuation logarithmicDepthBuffer s [...]
+function(c,e,h,l){var k,m,p,n,q,s=d[c.type];k=q=n=p=m=0;for(var t=e.length;k<t;k++){var v=e[k];!1!==v.visible&&(v instanceof THREE.DirectionalLight&&m++,v instanceof THREE.PointLight&&p++,v instanceof THREE.SpotLight&&n++,v instanceof THREE.HemisphereLight&&q++)}for(var v=k=t=0,u=e.length;v<u;v++){var w=e[v];w.castShadow&&((w instanceof THREE.SpotLight||w instanceof THREE.DirectionalLight)&&t++,w instanceof THREE.PointLight&&(t++,k++))}e=t;b.floatVertexTextures&&l&&l.skeleton&&l.skeleton [...]
+t=1024:(t=Math.floor((b.maxVertexUniforms-20)/4),void 0!==l&&l instanceof THREE.SkinnedMesh&&(t=Math.min(l.skeleton.bones.length,t),t<l.skeleton.bones.length&&console.warn("WebGLRenderer: too many bones - "+l.skeleton.bones.length+", this GPU supports just "+t+" (try OpenGL instead of ANGLE)")));v=a.getPrecision();null!==c.precision&&(v=b.getMaxPrecision(c.precision),v!==c.precision&&console.warn("THREE.WebGLRenderer.initMaterial:",c.precision,"not supported, using",v,"instead."));return [...]
+precision:v,supportsVertexTextures:b.vertexTextures,map:!!c.map,envMap:!!c.envMap,envMapMode:c.envMap&&c.envMap.mapping,lightMap:!!c.lightMap,aoMap:!!c.aoMap,emissiveMap:!!c.emissiveMap,bumpMap:!!c.bumpMap,normalMap:!!c.normalMap,displacementMap:!!c.displacementMap,specularMap:!!c.specularMap,alphaMap:!!c.alphaMap,combine:c.combine,vertexColors:c.vertexColors,fog:h,useFog:c.fog,fogExp:h instanceof THREE.FogExp2,flatShading:c.shading===THREE.FlatShading,sizeAttenuation:c.sizeAttenuation,l [...]
+skinning:c.skinning,maxBones:t,useVertexTexture:b.floatVertexTextures&&l&&l.skeleton&&l.skeleton.useVertexTexture,morphTargets:c.morphTargets,morphNormals:c.morphNormals,maxMorphTargets:a.maxMorphTargets,maxMorphNormals:a.maxMorphNormals,maxDirLights:m,maxPointLights:p,maxSpotLights:n,maxHemiLights:q,maxShadows:e,pointLightShadows:k,shadowMapEnabled:a.shadowMap.enabled&&l.receiveShadow&&0<e,shadowMapType:a.shadowMap.type,shadowMapDebug:a.shadowMap.debug,alphaTest:c.alphaTest,metal:c.meta [...]
+THREE.DoubleSide,flipSided:c.side===THREE.BackSide}};this.getProgramCode=function(a,b){var c=[];b.shaderID?c.push(b.shaderID):(c.push(a.fragmentShader),c.push(a.vertexShader));if(void 0!==a.defines)for(var d in a.defines)c.push(d),c.push(a.defines[d]);for(d=0;d<e.length;d++){var k=e[d];c.push(k);c.push(b[k])}return c.join()};this.acquireProgram=function(b,d,e){for(var l,k=0,m=c.length;k<m;k++){var p=c[k];if(p.code===e){l=p;++l.usedTimes;break}}void 0===l&&(l=new THREE.WebGLProgram(a,e,b, [...]
+return l};this.releaseProgram=function(a){if(0===--a.usedTimes){var b=c.indexOf(a);c[b]=c[c.length-1];c.pop();a.destroy()}};this.programs=c};THREE.WebGLProperties=function(){var a={};this.get=function(b){b=b.uuid;var c=a[b];void 0===c&&(c={},a[b]=c);return c};this.delete=function(b){delete a[b.uuid]};this.clear=function(){a={}}};
+THREE.WebGLShader=function(){function a(a){a=a.split("\n");for(var c=0;c<a.length;c++)a[c]=c+1+": "+a[c];return a.join("\n")}return function(b,c,d){var e=b.createShader(c);b.shaderSource(e,d);b.compileShader(e);!1===b.getShaderParameter(e,b.COMPILE_STATUS)&&console.error("THREE.WebGLShader: Shader couldn't compile.");""!==b.getShaderInfoLog(e)&&console.warn("THREE.WebGLShader: gl.getShaderInfoLog()",c===b.VERTEX_SHADER?"vertex":"fragment",b.getShaderInfoLog(e),a(d));return e}}();
+THREE.WebGLShadowMap=function(a,b,c){function d(a,b,c,d){var e=a.geometry,f=null,f=n,g=a.customDepthMaterial;c&&(f=q,g=a.customDistanceMaterial);g?f=g:(a=a instanceof THREE.SkinnedMesh&&b.skinning,g=0,void 0!==e.morphTargets&&0<e.morphTargets.length&&b.morphTargets&&(g|=1),a&&(g|=2),f=f[g]);f.visible=b.visible;f.wireframe=b.wireframe;f.wireframeLinewidth=b.wireframeLinewidth;c&&void 0!==f.uniforms.lightPos&&f.uniforms.lightPos.value.copy(d);return f}function e(a,b){if(!1!==a.visible){(a  [...]
+THREE.Mesh||a instanceof THREE.Line||a instanceof THREE.Points)&&a.castShadow&&(!1===a.frustumCulled||!0===h.intersectsObject(a))&&!0===a.material.visible&&(a.modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld),p.push(a));for(var c=a.children,d=0,f=c.length;d<f;d++)e(c[d],b)}}var g=a.context,f=a.state,h=new THREE.Frustum,l=new THREE.Matrix4;new THREE.Vector3;new THREE.Vector3;for(var k=new THREE.Vector3,m=new THREE.Vector3,p=[],n=Array(4),q=Array(4),s=[new THREE.Vector3( [...]
+0,0),new THREE.Vector3(0,0,1),new THREE.Vector3(0,0,-1),new THREE.Vector3(0,1,0),new THREE.Vector3(0,-1,0)],t=[new THREE.Vector3(0,1,0),new THREE.Vector3(0,1,0),new THREE.Vector3(0,1,0),new THREE.Vector3(0,1,0),new THREE.Vector3(0,0,1),new THREE.Vector3(0,0,-1)],v=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4],u=new THREE.Vector4,w=THREE.ShaderLib.depthRGBA,D=THREE.UniformsUtils.clone(w.uniforms),x=THREE.ShaderLib.distanceRGB [...]
+y=0;4!==y;++y){var z=0!==(y&1),A=0!==(y&2),J=new THREE.ShaderMaterial({uniforms:D,vertexShader:w.vertexShader,fragmentShader:w.fragmentShader,morphTargets:z,skinning:A});J._shadowPass=!0;n[y]=J;z=new THREE.ShaderMaterial({uniforms:B,vertexShader:x.vertexShader,fragmentShader:x.fragmentShader,morphTargets:z,skinning:A});z._shadowPass=!0;q[y]=z}var F=this;this.enabled=!1;this.autoUpdate=!0;this.needsUpdate=!1;this.type=THREE.PCFShadowMap;this.cullFace=THREE.CullFaceFront;this.render=functi [...]
+w;if(!1!==F.enabled&&(!1!==F.autoUpdate||!1!==F.needsUpdate)){g.clearColor(1,1,1,1);f.disable(g.BLEND);f.enable(g.CULL_FACE);g.frontFace(g.CCW);g.cullFace(F.cullFace===THREE.CullFaceFront?g.FRONT:g.BACK);f.setDepthTest(!0);a.getViewport(u);for(var x=0,D=b.length;x<D;x++){var y=b[x];if(!0===y.castShadow){var z=y.shadow,B=z.camera,A=z.mapSize;if(y instanceof THREE.PointLight){q=6;w=!0;var H=A.x/4,J=A.y/2;v[0].set(2*H,J,H,J);v[1].set(0,J,H,J);v[2].set(3*H,J,H,J);v[3].set(H,J,H,J);v[4].set(3 [...]
+v[5].set(H,0,H,J)}else q=1,w=!1;null===z.map&&(H=THREE.LinearFilter,F.type===THREE.PCFSoftShadowMap&&(H=THREE.NearestFilter),z.map=new THREE.WebGLRenderTarget(A.x,A.y,{minFilter:H,magFilter:H,format:THREE.RGBAFormat}),z.matrix=new THREE.Matrix4,y instanceof THREE.SpotLight&&(B.aspect=A.x/A.y),B.updateProjectionMatrix());A=z.map;z=z.matrix;m.setFromMatrixPosition(y.matrixWorld);B.position.copy(m);a.setRenderTarget(A);a.clear();for(A=0;A<q;A++)for(w?(k.copy(B.position),k.add(s[A]),B.up.cop [...]
+H=v[A],a.setViewport(H.x,H.y,H.z,H.w)):(k.setFromMatrixPosition(y.target.matrixWorld),B.lookAt(k)),B.updateMatrixWorld(),B.matrixWorldInverse.getInverse(B.matrixWorld),z.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),z.multiply(B.projectionMatrix),z.multiply(B.matrixWorldInverse),l.multiplyMatrices(B.projectionMatrix,B.matrixWorldInverse),h.setFromMatrix(l),p.length=0,e(n,B),H=0,J=p.length;H<J;H++){var G=p[H],ia=c.update(G),U=G.material;if(U instanceof THREE.MeshFaceMaterial)for(var X=ia.gro [...]
+da=0,ca=X.length;da<ca;da++){var ga=X[da],Z=U[ga.materialIndex];!0===Z.visible&&(Z=d(G,Z,w,m),a.renderBufferDirect(B,b,null,ia,Z,G,ga))}else Z=d(G,U,w,m),a.renderBufferDirect(B,b,null,ia,Z,G,null)}a.resetGLState()}}a.setViewport(u.x,u.y,u.z,u.w);n=a.getClearColor();q=a.getClearAlpha();a.setClearColor(n,q);f.enable(g.BLEND);F.cullFace===THREE.CullFaceFront&&g.cullFace(g.BACK);a.resetGLState();F.needsUpdate=!1}}};
+THREE.WebGLState=function(a,b,c){var d=this,e=new Uint8Array(16),g=new Uint8Array(16),f=new Uint8Array(16),h={},l=null,k=null,m=null,p=null,n=null,q=null,s=null,t=null,v=null,u=null,w=null,D=null,x=null,B=null,y=null,z=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),A=void 0,J={};this.init=function(){a.clearColor(0,0,0,1);a.clearDepth(1);a.clearStencil(0);this.enable(a.DEPTH_TEST);a.depthFunc(a.LEQUAL);a.frontFace(a.CCW);a.cullFace(a.BACK);this.enable(a.CULL_FACE);this.enable(a.BLEND);a.blendE [...]
+a.blendFunc(a.SRC_ALPHA,a.ONE_MINUS_SRC_ALPHA)};this.initAttributes=function(){for(var a=0,b=e.length;a<b;a++)e[a]=0};this.enableAttribute=function(c){e[c]=1;0===g[c]&&(a.enableVertexAttribArray(c),g[c]=1);0!==f[c]&&(b.get("ANGLE_instanced_arrays").vertexAttribDivisorANGLE(c,0),f[c]=0)};this.enableAttributeAndDivisor=function(b,c,d){e[b]=1;0===g[b]&&(a.enableVertexAttribArray(b),g[b]=1);f[b]!==c&&(d.vertexAttribDivisorANGLE(b,c),f[b]=c)};this.disableUnusedAttributes=function(){for(var b= [...]
+c;b++)g[b]!==e[b]&&(a.disableVertexAttribArray(b),g[b]=0)};this.enable=function(b){!0!==h[b]&&(a.enable(b),h[b]=!0)};this.disable=function(b){!1!==h[b]&&(a.disable(b),h[b]=!1)};this.getCompressedTextureFormats=function(){if(null===l&&(l=[],b.get("WEBGL_compressed_texture_pvrtc")||b.get("WEBGL_compressed_texture_s3tc")))for(var c=a.getParameter(a.COMPRESSED_TEXTURE_FORMATS),d=0;d<c.length;d++)l.push(c[d]);return l};this.setBlending=function(b,d,e,f,g,h,l){b!==k&&(b===THREE.NoBlending?this [...]
+b===THREE.AdditiveBlending?(this.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.SRC_ALPHA,a.ONE)):b===THREE.SubtractiveBlending?(this.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.ONE_MINUS_SRC_COLOR)):b===THREE.MultiplyBlending?(this.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.SRC_COLOR)):b===THREE.CustomBlending?this.enable(a.BLEND):(this.enable(a.BLEND),a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD),a.blendFuncSeparate(a.SRC_ALPHA,a.O [...]
+a.ONE,a.ONE_MINUS_SRC_ALPHA)),k=b);if(b===THREE.CustomBlending){g=g||d;h=h||e;l=l||f;if(d!==m||g!==q)a.blendEquationSeparate(c(d),c(g)),m=d,q=g;if(e!==p||f!==n||h!==s||l!==t)a.blendFuncSeparate(c(e),c(f),c(h),c(l)),p=e,n=f,s=h,t=l}else t=s=q=n=p=m=null};this.setDepthFunc=function(b){if(v!==b){if(b)switch(b){case THREE.NeverDepth:a.depthFunc(a.NEVER);break;case THREE.AlwaysDepth:a.depthFunc(a.ALWAYS);break;case THREE.LessDepth:a.depthFunc(a.LESS);break;case THREE.LessEqualDepth:a.depthFun [...]
+break;case THREE.EqualDepth:a.depthFunc(a.EQUAL);break;case THREE.GreaterEqualDepth:a.depthFunc(a.GEQUAL);break;case THREE.GreaterDepth:a.depthFunc(a.GREATER);break;case THREE.NotEqualDepth:a.depthFunc(a.NOTEQUAL);break;default:a.depthFunc(a.LEQUAL)}else a.depthFunc(a.LEQUAL);v=b}};this.setDepthTest=function(b){b?this.enable(a.DEPTH_TEST):this.disable(a.DEPTH_TEST)};this.setDepthWrite=function(b){u!==b&&(a.depthMask(b),u=b)};this.setColorWrite=function(b){w!==b&&(a.colorMask(b,b,b,b),w=b [...]
+function(b){D!==b&&(b?a.frontFace(a.CW):a.frontFace(a.CCW),D=b)};this.setLineWidth=function(b){b!==x&&(a.lineWidth(b),x=b)};this.setPolygonOffset=function(b,c,d){b?this.enable(a.POLYGON_OFFSET_FILL):this.disable(a.POLYGON_OFFSET_FILL);!b||B===c&&y===d||(a.polygonOffset(c,d),B=c,y=d)};this.setScissorTest=function(b){b?this.enable(a.SCISSOR_TEST):this.disable(a.SCISSOR_TEST)};this.activeTexture=function(b){void 0===b&&(b=a.TEXTURE0+z-1);A!==b&&(a.activeTexture(b),A=b)};this.bindTexture=fun [...]
+A&&d.activeTexture();var e=J[A];void 0===e&&(e={type:void 0,texture:void 0},J[A]=e);if(e.type!==b||e.texture!==c)a.bindTexture(b,c),e.type=b,e.texture=c};this.compressedTexImage2D=function(){try{a.compressedTexImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.texImage2D=function(){try{a.texImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.reset=function(){for(var b=0;b<g.length;b++)1===g[b]&&(a.disableVertexAttribArray(b),g[b]=0);h={};D=w=u=k=l=null}};
+THREE.LensFlarePlugin=function(a,b){var c,d,e,g,f,h,l,k,m,p,n=a.context,q=a.state,s,t,v,u,w,D;this.render=function(x,B,y,z){if(0!==b.length){x=new THREE.Vector3;var A=z/y,J=.5*y,F=.5*z,C=16/z,N=new THREE.Vector2(C*A,C),L=new THREE.Vector3(1,1,0),Q=new THREE.Vector2(1,1);if(void 0===v){var C=new Float32Array([-1,-1,0,0,1,-1,1,0,1,1,1,1,-1,1,0,1]),M=new Uint16Array([0,1,2,0,2,3]);s=n.createBuffer();t=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,s);n.bufferData(n.ARRAY_BUFFER,C,n.STATIC_DRA [...]
+t);n.bufferData(n.ELEMENT_ARRAY_BUFFER,M,n.STATIC_DRAW);w=n.createTexture();D=n.createTexture();q.bindTexture(n.TEXTURE_2D,w);n.texImage2D(n.TEXTURE_2D,0,n.RGB,16,16,0,n.RGB,n.UNSIGNED_BYTE,null);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST);q.bindTexture(n.TEXTURE_2D,D);n.texImage2D(n.TEX [...]
+n.RGBA,16,16,0,n.RGBA,n.UNSIGNED_BYTE,null);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST);var C=(u=0<n.getParameter(n.MAX_VERTEX_TEXTURE_IMAGE_UNITS))?{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D  [...]
+fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif ( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if ( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}:{vertexShader:"uniform lowp [...]
+fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif ( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if ( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 [...]
+M=n.createProgram(),K=n.createShader(n.FRAGMENT_SHADER),E=n.createShader(n.VERTEX_SHADER),O="precision "+a.getPrecision()+" float;\n";n.shaderSource(K,O+C.fragmentShader);n.shaderSource(E,O+C.vertexShader);n.compileShader(K);n.compileShader(E);n.attachShader(M,K);n.attachShader(M,E);n.linkProgram(M);v=M;m=n.getAttribLocation(v,"position");p=n.getAttribLocation(v,"uv");c=n.getUniformLocation(v,"renderType");d=n.getUniformLocation(v,"map");e=n.getUniformLocation(v,"occlusionMap");g=n.getUn [...]
+"opacity");f=n.getUniformLocation(v,"color");h=n.getUniformLocation(v,"scale");l=n.getUniformLocation(v,"rotation");k=n.getUniformLocation(v,"screenPosition")}n.useProgram(v);q.initAttributes();q.enableAttribute(m);q.enableAttribute(p);q.disableUnusedAttributes();n.uniform1i(e,0);n.uniform1i(d,1);n.bindBuffer(n.ARRAY_BUFFER,s);n.vertexAttribPointer(m,2,n.FLOAT,!1,16,0);n.vertexAttribPointer(p,2,n.FLOAT,!1,16,8);n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,t);q.disable(n.CULL_FACE);n.depthMask(!1) [...]
+b.length;M<K;M++)if(C=16/z,N.set(C*A,C),E=b[M],x.set(E.matrixWorld.elements[12],E.matrixWorld.elements[13],E.matrixWorld.elements[14]),x.applyMatrix4(B.matrixWorldInverse),x.applyProjection(B.projectionMatrix),L.copy(x),Q.x=L.x*J+J,Q.y=L.y*F+F,u||0<Q.x&&Q.x<y&&0<Q.y&&Q.y<z){q.activeTexture(n.TEXTURE0);q.bindTexture(n.TEXTURE_2D,null);q.activeTexture(n.TEXTURE1);q.bindTexture(n.TEXTURE_2D,w);n.copyTexImage2D(n.TEXTURE_2D,0,n.RGB,Q.x-8,Q.y-8,16,16,0);n.uniform1i(c,0);n.uniform2f(h,N.x,N.y) [...]
+L.x,L.y,L.z);q.disable(n.BLEND);q.enable(n.DEPTH_TEST);n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT,0);q.activeTexture(n.TEXTURE0);q.bindTexture(n.TEXTURE_2D,D);n.copyTexImage2D(n.TEXTURE_2D,0,n.RGBA,Q.x-8,Q.y-8,16,16,0);n.uniform1i(c,1);q.disable(n.DEPTH_TEST);q.activeTexture(n.TEXTURE1);q.bindTexture(n.TEXTURE_2D,w);n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT,0);E.positionScreen.copy(L);E.customUpdateCallback?E.customUpdateCallback(E):E.updateLensFlares();n.uniform1i(c,2);q.enable(n [...]
+0,T=E.lensFlares.length;O<T;O++){var H=E.lensFlares[O];.001<H.opacity&&.001<H.scale&&(L.x=H.x,L.y=H.y,L.z=H.z,C=H.size*H.scale/z,N.x=C*A,N.y=C,n.uniform3f(k,L.x,L.y,L.z),n.uniform2f(h,N.x,N.y),n.uniform1f(l,H.rotation),n.uniform1f(g,H.opacity),n.uniform3f(f,H.color.r,H.color.g,H.color.b),q.setBlending(H.blending,H.blendEquation,H.blendSrc,H.blendDst),a.setTexture(H.texture,1),n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT,0))}}q.enable(n.CULL_FACE);q.enable(n.DEPTH_TEST);n.depthMask(!0);a [...]
+THREE.SpritePlugin=function(a,b){var c,d,e,g,f,h,l,k,m,p,n,q,s,t,v,u,w;function D(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var x=a.context,B=a.state,y,z,A,J,F=new THREE.Vector3,C=new THREE.Quaternion,N=new THREE.Vector3;this.render=function(L,Q){if(0!==b.length){if(void 0===A){var M=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),K=new Uint16Array([0,1,2,0,2,3]);y=x.createBuffer();z=x.createBuffer();x.bindBuffer(x.ARRAY_BUFFER,y);x.bufferData(x.ARRAY_BUFFER,M,x.STATIC_DRAW [...]
+z);x.bufferData(x.ELEMENT_ARRAY_BUFFER,K,x.STATIC_DRAW);var M=x.createProgram(),K=x.createShader(x.VERTEX_SHADER),E=x.createShader(x.FRAGMENT_SHADER);x.shaderSource(K,["precision "+a.getPrecision()+" float;","uniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPos [...]
+x.shaderSource(E,["precision "+a.getPrecision()+" float;","uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_F [...]
+x.compileShader(K);x.compileShader(E);x.attachShader(M,K);x.attachShader(M,E);x.linkProgram(M);A=M;u=x.getAttribLocation(A,"position");w=x.getAttribLocation(A,"uv");c=x.getUniformLocation(A,"uvOffset");d=x.getUniformLocation(A,"uvScale");e=x.getUniformLocation(A,"rotation");g=x.getUniformLocation(A,"scale");f=x.getUniformLocation(A,"color");h=x.getUniformLocation(A,"map");l=x.getUniformLocation(A,"opacity");k=x.getUniformLocation(A,"modelViewMatrix");m=x.getUniformLocation(A,"projectionM [...]
+x.getUniformLocation(A,"fogType");n=x.getUniformLocation(A,"fogDensity");q=x.getUniformLocation(A,"fogNear");s=x.getUniformLocation(A,"fogFar");t=x.getUniformLocation(A,"fogColor");v=x.getUniformLocation(A,"alphaTest");M=document.createElement("canvas");M.width=8;M.height=8;K=M.getContext("2d");K.fillStyle="white";K.fillRect(0,0,8,8);J=new THREE.Texture(M);J.needsUpdate=!0}x.useProgram(A);B.initAttributes();B.enableAttribute(u);B.enableAttribute(w);B.disableUnusedAttributes();B.disable(x [...]
+B.enable(x.BLEND);x.bindBuffer(x.ARRAY_BUFFER,y);x.vertexAttribPointer(u,2,x.FLOAT,!1,16,0);x.vertexAttribPointer(w,2,x.FLOAT,!1,16,8);x.bindBuffer(x.ELEMENT_ARRAY_BUFFER,z);x.uniformMatrix4fv(m,!1,Q.projectionMatrix.elements);B.activeTexture(x.TEXTURE0);x.uniform1i(h,0);K=M=0;(E=L.fog)?(x.uniform3f(t,E.color.r,E.color.g,E.color.b),E instanceof THREE.Fog?(x.uniform1f(q,E.near),x.uniform1f(s,E.far),x.uniform1i(p,1),K=M=1):E instanceof THREE.FogExp2&&(x.uniform1f(n,E.density),x.uniform1i(p [...]
+(x.uniform1i(p,0),K=M=0);for(var E=0,O=b.length;E<O;E++){var T=b[E];T.modelViewMatrix.multiplyMatrices(Q.matrixWorldInverse,T.matrixWorld);T.z=-T.modelViewMatrix.elements[14]}b.sort(D);for(var H=[],E=0,O=b.length;E<O;E++){var T=b[E],R=T.material;x.uniform1f(v,R.alphaTest);x.uniformMatrix4fv(k,!1,T.modelViewMatrix.elements);T.matrixWorld.decompose(F,C,N);H[0]=N.x;H[1]=N.y;T=0;L.fog&&R.fog&&(T=K);M!==T&&(x.uniform1i(p,T),M=T);null!==R.map?(x.uniform2f(c,R.map.offset.x,R.map.offset.y),x.uni [...]
+R.map.repeat.x,R.map.repeat.y)):(x.uniform2f(c,0,0),x.uniform2f(d,1,1));x.uniform1f(l,R.opacity);x.uniform3f(f,R.color.r,R.color.g,R.color.b);x.uniform1f(e,R.rotation);x.uniform2fv(g,H);B.setBlending(R.blending,R.blendEquation,R.blendSrc,R.blendDst);B.setDepthTest(R.depthTest);B.setDepthWrite(R.depthWrite);R.map&&R.map.image&&R.map.image.width?a.setTexture(R.map,0):a.setTexture(J,0);x.drawElements(x.TRIANGLES,6,x.UNSIGNED_SHORT,0)}B.enable(x.CULL_FACE);a.resetGLState()}}};
+THREE.CurveUtils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a,b,c,d,e){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){a=.5*(c-a);d=.5*(d-b);var g=e*e;return(2*b-2*c+a+d)*e*g+(-3*b+3*c-2*a-d)*g+a*e+b}};
+THREE.GeometryUtils={merge:function(a,b,c){console.warn("THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.");var d;b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,b=b.geometry);a.merge(b,d,c)},center:function(a){console.warn("THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.");return a.center()}};
+THREE.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c,d){console.warn("THREE.ImageUtils.loadTexture is being deprecated. Use THREE.TextureLoader() instead.");var e=new THREE.TextureLoader;e.setCrossOrigin(this.crossOrigin);a=e.load(a,c,void 0,d);b&&(a.mapping=b);return a},loadTextureCube:function(a,b,c,d){console.warn("THREE.ImageUtils.loadTextureCube is being deprecated. Use THREE.CubeTextureLoader() instead.");var e=new THREE.CubeTextureLoader;e.setCrossOrigin(this.crossOrigi [...]
+c,void 0,d);b&&(a.mapping=b);return a},loadCompressedTexture:function(){console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")},loadCompressedTextureCube:function(){console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")}};
+THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Group,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
+THREE.ShapeUtils={area:function(a){for(var b=a.length,c=0,d=b-1,e=0;e<b;d=e++)c+=a[d].x*a[e].y-a[e].x*a[d].y;return.5*c},triangulate:function(){return function(a,b){var c=a.length;if(3>c)return null;var d=[],e=[],g=[],f,h,l;if(0<THREE.ShapeUtils.area(a))for(h=0;h<c;h++)e[h]=h;else for(h=0;h<c;h++)e[h]=c-1-h;var k=2*c;for(h=c-1;2<c;){if(0>=k--){console.warn("THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()");break}f=h;c<=f&&(f=0);h=f+1;c<=h&&(h=0);l=h+1;c<=l&&(l=0);var m; [...]
+m=void 0,n=void 0,q=void 0,s=void 0,t=void 0,v=void 0,u=void 0,w=void 0,p=a[e[f]].x,n=a[e[f]].y,q=a[e[h]].x,s=a[e[h]].y,t=a[e[l]].x,v=a[e[l]].y;if(Number.EPSILON>(q-p)*(v-n)-(s-n)*(t-p))m=!1;else{var D=void 0,x=void 0,B=void 0,y=void 0,z=void 0,A=void 0,J=void 0,F=void 0,C=void 0,N=void 0,C=F=J=w=u=void 0,D=t-q,x=v-s,B=p-t,y=n-v,z=q-p,A=s-n;for(m=0;m<c;m++)if(u=a[e[m]].x,w=a[e[m]].y,!(u===p&&w===n||u===q&&w===s||u===t&&w===v)&&(J=u-p,F=w-n,C=u-q,N=w-s,u-=t,w-=v,C=D*N-x*C,J=z*F-A*J,F=B*w- [...]
+F>=-Number.EPSILON&&J>=-Number.EPSILON)){m=!1;break a}m=!0}}if(m){d.push([a[e[f]],a[e[h]],a[e[l]]]);g.push([e[f],e[h],e[l]]);f=h;for(l=h+1;l<c;f++,l++)e[f]=e[l];c--;k=2*c}}return b?g:d}}(),triangulateShape:function(a,b){function c(a,b,c){return a.x!==b.x?a.x<b.x?a.x<=c.x&&c.x<=b.x:b.x<=c.x&&c.x<=a.x:a.y<b.y?a.y<=c.y&&c.y<=b.y:b.y<=c.y&&c.y<=a.y}function d(a,b,d,e,f){var g=b.x-a.x,h=b.y-a.y,k=e.x-d.x,l=e.y-d.y,m=a.x-d.x,p=a.y-d.y,z=h*k-g*l,A=h*m-g*p;if(Math.abs(z)>Number.EPSILON){if(0<z){ [...]
+z)return[];k=l*m-k*p;if(0>k||k>z)return[]}else{if(0<A||A<z)return[];k=l*m-k*p;if(0<k||k<z)return[]}if(0===k)return!f||0!==A&&A!==z?[a]:[];if(k===z)return!f||0!==A&&A!==z?[b]:[];if(0===A)return[d];if(A===z)return[e];f=k/z;return[{x:a.x+f*g,y:a.y+f*h}]}if(0!==A||l*m!==k*p)return[];h=0===g&&0===h;k=0===k&&0===l;if(h&&k)return a.x!==d.x||a.y!==d.y?[]:[a];if(h)return c(d,e,a)?[a]:[];if(k)return c(a,b,d)?[d]:[];0!==g?(a.x<b.x?(g=a,k=a.x,h=b,a=b.x):(g=b,k=b.x,h=a,a=a.x),d.x<e.x?(b=d,z=d.x,l=e,d [...]
+e,z=e.x,l=d,d=d.x)):(a.y<b.y?(g=a,k=a.y,h=b,a=b.y):(g=b,k=b.y,h=a,a=a.y),d.y<e.y?(b=d,z=d.y,l=e,d=e.y):(b=e,z=e.y,l=d,d=d.y));return k<=z?a<z?[]:a===z?f?[]:[b]:a<=d?[b,h]:[b,l]:k>d?[]:k===d?f?[]:[g]:a<=d?[g,h]:[g,l]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return Math.abs(a)>Number.EPSILON?(b=g*c-d*b,0<a?0<=e&&0<=b:0<=e||0<=b):0<e}var g,f,h,l,k,m={};h=a.concat();g=0;for(f=b.length;g<f;g++)Array.prototype.push.apply(h,b[g] [...]
+h.length;g<f;g++)k=h[g].x+":"+h[g].y,void 0!==m[k]&&console.warn("THREE.Shape: Duplicate point",k),m[k]=g;g=function(a,b){function c(a,b){var d=h.length-1,f=a-1;0>f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1;d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;c<h.length;c++)if(e=c+1,e%=h.length,e=d(a,b,h[c],h[e],!0),0<e.length)return!0;return!1}function g(a,c){var e,f,h,k;for(e=0;e<l.length;e++)for [...]
+h=0;h<f.length;h++)if(k=h+1,k%=f.length,k=d(a,c,f[h],f[k],!0),0<k.length)return!0;return!1}var h=a.concat(),k,l=[],m,p,y,z,A,J=[],F,C,N,L=0;for(m=b.length;L<m;L++)l.push(L);F=0;for(var Q=2*l.length;0<l.length;){Q--;if(0>Q){console.log("Infinite Loop! Holes left:"+l.length+", Probably Hole outside Shape!");break}for(p=F;p<h.length;p++){y=h[p];m=-1;for(L=0;L<l.length;L++)if(z=l[L],A=y.x+":"+y.y+":"+z,void 0===J[A]){k=b[z];for(C=0;C<k.length;C++)if(z=k[C],c(p,C)&&!f(y,z)&&!g(y,z)){m=C;l.spl [...]
+F=h.slice(0,p+1);z=h.slice(p);C=k.slice(m);N=k.slice(0,m+1);h=F.concat(C).concat(N).concat(z);F=p;break}if(0<=m)break;J[A]=!0}if(0<=m)break}}return h}(a,b);var p=THREE.ShapeUtils.triangulate(g,!1);g=0;for(f=p.length;g<f;g++)for(l=p[g],h=0;3>h;h++)k=l[h].x+":"+l[h].y,k=m[k],void 0!==k&&(l[h]=k);return p.concat()},isClockWise:function(a){return 0>THREE.ShapeUtils.area(a)},b2:function(){return function(a,b,c,d){var e=1-a;return e*e*b+2*(1-a)*a*c+a*a*d}}(),b3:function(){return function(a,b,c [...]
+1-a,f=1-a;return g*g*g*b+3*f*f*a*c+3*(1-a)*a*a*d+a*a*a*e}}()};THREE.Audio=function(a){THREE.Object3D.call(this);this.type="Audio";this.context=a.context;this.source=this.context.createBufferSource();this.source.onended=this.onEnded.bind(this);this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.panner=this.context.createPanner();this.panner.connect(this.gain);this.autoplay=!1;this.startTime=0;this.playbackRate=1;this.isPlaying=!1};THREE.Audio.prototype=Obj [...]
+THREE.Audio.prototype.constructor=THREE.Audio;THREE.Audio.prototype.load=function(a){var b=this,c=new XMLHttpRequest;c.open("GET",a,!0);c.responseType="arraybuffer";c.onload=function(a){b.context.decodeAudioData(this.response,function(a){b.source.buffer=a;b.autoplay&&b.play()})};c.send();return this};
+THREE.Audio.prototype.play=function(){if(!0===this.isPlaying)console.warn("THREE.Audio: Audio is already playing.");else{var a=this.context.createBufferSource();a.buffer=this.source.buffer;a.loop=this.source.loop;a.onended=this.source.onended;a.start(0,this.startTime);a.playbackRate.value=this.playbackRate;this.isPlaying=!0;this.source=a;this.connect()}};THREE.Audio.prototype.pause=function(){this.source.stop();this.startTime=this.context.currentTime};
+THREE.Audio.prototype.stop=function(){this.source.stop();this.startTime=0};THREE.Audio.prototype.connect=function(){void 0!==this.filter?(this.source.connect(this.filter),this.filter.connect(this.panner)):this.source.connect(this.panner)};THREE.Audio.prototype.disconnect=function(){void 0!==this.filter?(this.source.disconnect(this.filter),this.filter.disconnect(this.panner)):this.source.disconnect(this.panner)};
+THREE.Audio.prototype.setFilter=function(a){!0===this.isPlaying?(this.disconnect(),this.filter=a,this.connect()):this.filter=a};THREE.Audio.prototype.getFilter=function(){return this.filter};THREE.Audio.prototype.setPlaybackRate=function(a){this.playbackRate=a;!0===this.isPlaying&&(this.source.playbackRate.value=this.playbackRate)};THREE.Audio.prototype.getPlaybackRate=function(){return this.playbackRate};THREE.Audio.prototype.onEnded=function(){this.isPlaying=!1};
+THREE.Audio.prototype.setLoop=function(a){this.source.loop=a};THREE.Audio.prototype.getLoop=function(){return this.source.loop};THREE.Audio.prototype.setRefDistance=function(a){this.panner.refDistance=a};THREE.Audio.prototype.getRefDistance=function(){return this.panner.refDistance};THREE.Audio.prototype.setRolloffFactor=function(a){this.panner.rolloffFactor=a};THREE.Audio.prototype.getRolloffFactor=function(){return this.panner.rolloffFactor};
+THREE.Audio.prototype.setVolume=function(a){this.gain.gain.value=a};THREE.Audio.prototype.getVolume=function(){return this.gain.gain.value};THREE.Audio.prototype.updateMatrixWorld=function(){var a=new THREE.Vector3;return function(b){THREE.Object3D.prototype.updateMatrixWorld.call(this,b);a.setFromMatrixPosition(this.matrixWorld);this.panner.setPosition(a.x,a.y,a.z)}}();THREE.AudioListener=function(){THREE.Object3D.call(this);this.type="AudioListener";this.context=new (window.AudioContex [...]
+THREE.AudioListener.prototype=Object.create(THREE.Object3D.prototype);THREE.AudioListener.prototype.constructor=THREE.AudioListener;
+THREE.AudioListener.prototype.updateMatrixWorld=function(){var a=new THREE.Vector3,b=new THREE.Quaternion,c=new THREE.Vector3,d=new THREE.Vector3;return function(e){THREE.Object3D.prototype.updateMatrixWorld.call(this,e);e=this.context.listener;var g=this.up;this.matrixWorld.decompose(a,b,c);d.set(0,0,-1).applyQuaternion(b);e.setPosition(a.x,a.y,a.z);e.setOrientation(d.x,d.y,d.z,g.x,g.y,g.z)}}();THREE.Curve=function(){};
+THREE.Curve.prototype={constructor:THREE.Curve,getPoint:function(a){console.warn("THREE.Curve: Warning, getPoint() not implemented!");return null},getPointAt:function(a){a=this.getUtoTmapping(a);return this.getPoint(a)},getPoints:function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPoint(b/a));return c},getSpacedPoints:function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPointAt(b/a));return c},getLength:function(){var a=this.getLengths();return a[a.length-1]},getLe [...]
+(a=this.__arcLengthDivisions?this.__arcLengthDivisions:200);if(this.cacheArcLengths&&this.cacheArcLengths.length===a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b=[],c,d=this.getPoint(0),e,g=0;b.push(0);for(e=1;e<=a;e++)c=this.getPoint(e/a),g+=c.distanceTo(d),b.push(g),d=c;return this.cacheArcLengths=b},updateArcLengths:function(){this.needsUpdate=!0;this.getLengths()},getUtoTmapping:function(a,b){var c=this.getLengths(),d=0,e=c.length,g;g=b?b:a*c[e-1];for(va [...]
+1,l;f<=h;)if(d=Math.floor(f+(h-f)/2),l=c[d]-g,0>l)f=d+1;else if(0<l)h=d-1;else{h=d;break}d=h;if(c[d]===g)return d/(e-1);f=c[d];return c=(d+(g-f)/(c[d+1]-f))/(e-1)},getTangent:function(a){var b=a-1E-4;a+=1E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);return this.getPoint(a).clone().sub(b).normalize()},getTangentAt:function(a){a=this.getUtoTmapping(a);return this.getTangent(a)}};THREE.Curve.Utils=THREE.CurveUtils;
+THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};THREE.CurvePath=function(){this.curves=[];this.autoClose=!1};THREE.CurvePath.prototype=Object.create(THREE.Curve.prototype);THREE.CurvePath.prototype.constructor=THREE.CurvePath;THREE.CurvePath.prototype.add=function(a){this.curves.push(a)};
+THREE.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new THREE.LineCurve(b,a))};THREE.CurvePath.prototype.getPoint=function(a){for(var b=a*this.getLength(),c=this.getCurveLengths(),d=0;d<c.length;){if(c[d]>=b)return a=this.curves[d],b=1-(c[d]-b)/a.getLength(),a.getPointAt(b);d++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]};
+THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[],b=0,c=0,d=this.curves.length;c<d;c++)b+=this.curves[c].getLength(),a.push(b);return this.cacheLengths=a};THREE.CurvePath.prototype.createPointsGeometry=function(a){a=this.getPoints(a,!0);return this.createGeometry(a)};THREE.CurvePath.prototype.createSpacedPointsGeometry=function(a){a=this.getSpacedPoints(a,!0);return this.createGeo [...]
+THREE.CurvePath.prototype.createGeometry=function(a){for(var b=new THREE.Geometry,c=0,d=a.length;c<d;c++){var e=a[c];b.vertices.push(new THREE.Vector3(e.x,e.y,e.z||0))}return b};THREE.Path=function(a){THREE.CurvePath.call(this);this.actions=[];a&&this.fromPoints(a)};THREE.Path.prototype=Object.create(THREE.CurvePath.prototype);THREE.Path.prototype.constructor=THREE.Path;THREE.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b]. [...]
+THREE.Path.prototype.moveTo=function(a,b){this.actions.push({action:"moveTo",args:[a,b]})};THREE.Path.prototype.lineTo=function(a,b){var c=this.actions[this.actions.length-1].args,c=new THREE.LineCurve(new THREE.Vector2(c[c.length-2],c[c.length-1]),new THREE.Vector2(a,b));this.curves.push(c);this.actions.push({action:"lineTo",args:[a,b]})};
+THREE.Path.prototype.quadraticCurveTo=function(a,b,c,d){var e=this.actions[this.actions.length-1].args,e=new THREE.QuadraticBezierCurve(new THREE.Vector2(e[e.length-2],e[e.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d));this.curves.push(e);this.actions.push({action:"quadraticCurveTo",args:[a,b,c,d]})};
+THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,e,g){var f=this.actions[this.actions.length-1].args,f=new THREE.CubicBezierCurve(new THREE.Vector2(f[f.length-2],f[f.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d),new THREE.Vector2(e,g));this.curves.push(f);this.actions.push({action:"bezierCurveTo",args:[a,b,c,d,e,g]})};
+THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:"splineThru",args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,g){var f=this.actions[this.actions.length-1].args;this.absarc(a+f[f.length-2],b+f[f.length-1],c,d,e,g)};
+THREE.Path.prototype.absarc=function(a,b,c,d,e,g){this.absellipse(a,b,c,c,d,e,g)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,g,f,h){var l=this.actions[this.actions.length-1].args;this.absellipse(a+l[l.length-2],b+l[l.length-1],c,d,e,g,f,h)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,g,f,h){var l=[a,b,c,d,e,g,f,h||0];a=new THREE.EllipseCurve(a,b,c,d,e,g,f,h);this.curves.push(a);a=a.getPoint(1);l.push(a.x);l.push(a.y);this.actions.push({action:"ellipse",args:l})};
+THREE.Path.prototype.getSpacedPoints=function(a,b){a||(a=40);for(var c=[],d=0;d<a;d++)c.push(this.getPoint(d/a));return c};
+THREE.Path.prototype.getPoints=function(a,b){a=a||12;for(var c=THREE.ShapeUtils.b2,d=THREE.ShapeUtils.b3,e=[],g,f,h,l,k,m,p,n,q,s,t=0,v=this.actions.length;t<v;t++){q=this.actions[t];var u=q.args;switch(q.action){case "moveTo":e.push(new THREE.Vector2(u[0],u[1]));break;case "lineTo":e.push(new THREE.Vector2(u[0],u[1]));break;case "quadraticCurveTo":g=u[2];f=u[3];k=u[0];m=u[1];0<e.length?(q=e[e.length-1],p=q.x,n=q.y):(q=this.actions[t-1].args,p=q[q.length-2],n=q[q.length-1]);for(u=1;u<=a; [...]
+q=c(s,p,k,g),s=c(s,n,m,f),e.push(new THREE.Vector2(q,s));break;case "bezierCurveTo":g=u[4];f=u[5];k=u[0];m=u[1];h=u[2];l=u[3];0<e.length?(q=e[e.length-1],p=q.x,n=q.y):(q=this.actions[t-1].args,p=q[q.length-2],n=q[q.length-1]);for(u=1;u<=a;u++)s=u/a,q=d(s,p,k,h,g),s=d(s,n,m,l,f),e.push(new THREE.Vector2(q,s));break;case "splineThru":q=this.actions[t-1].args;s=[new THREE.Vector2(q[q.length-2],q[q.length-1])];q=a*u[0].length;s=s.concat(u[0]);s=new THREE.SplineCurve(s);for(u=1;u<=q;u++)e.pus [...]
+q));break;case "arc":g=u[0];f=u[1];m=u[2];h=u[3];q=u[4];k=!!u[5];p=q-h;n=2*a;for(u=1;u<=n;u++)s=u/n,k||(s=1-s),s=h+s*p,q=g+m*Math.cos(s),s=f+m*Math.sin(s),e.push(new THREE.Vector2(q,s));break;case "ellipse":g=u[0];f=u[1];m=u[2];l=u[3];h=u[4];q=u[5];k=!!u[6];var w=u[7];p=q-h;n=2*a;var D,x;0!==w&&(D=Math.cos(w),x=Math.sin(w));for(u=1;u<=n;u++){s=u/n;k||(s=1-s);s=h+s*p;q=g+m*Math.cos(s);s=f+l*Math.sin(s);if(0!==w){var B=q;q=(B-g)*D-(s-f)*x+g;s=(B-g)*x+(s-f)*D+f}e.push(new THREE.Vector2(q,s) [...]
+1];Math.abs(c.x-e[0].x)<Number.EPSILON&&Math.abs(c.y-e[0].y)<Number.EPSILON&&e.splice(e.length-1,1);b&&e.push(e[0]);return e};
+THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new THREE.Shape;f.actions=e.actions;f.curves=e.curves;b.push(f)}return b}function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],h=b[f],k=h.x-g.x,l=h.y-g.y;if(Math.abs(l)>Number.EPSILON){if(0>l&&(g=b[f],k=-k,h=b[e],l=-l),!(a.y<g.y||a.y>h.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=l*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x& [...]
+g.x<=a.x&&a.x<=h.x))return!0}return d}var e=THREE.ShapeUtils.isClockWise,g=function(a){for(var b=[],c=new THREE.Path,d=0,e=a.length;d<e;d++){var f=a[d],g=f.args,f=f.action;"moveTo"===f&&0!==c.actions.length&&(b.push(c),c=new THREE.Path);c[f].apply(c,g)}0!==c.actions.length&&b.push(c);return b}(this.actions);if(0===g.length)return[];if(!0===b)return c(g);var f,h,l,k=[];if(1===g.length)return h=g[0],l=new THREE.Shape,l.actions=h.actions,l.curves=h.curves,k.push(l),k;var m=!e(g[0].getPoints [...]
+m;l=[];var p=[],n=[],q=0,s;p[q]=void 0;n[q]=[];for(var t=0,v=g.length;t<v;t++)h=g[t],s=h.getPoints(),f=e(s),(f=a?!f:f)?(!m&&p[q]&&q++,p[q]={s:new THREE.Shape,p:s},p[q].s.actions=h.actions,p[q].s.curves=h.curves,m&&q++,n[q]=[]):n[q].push({h:h,p:s[0]});if(!p[0])return c(g);if(1<p.length){t=!1;h=[];e=0;for(g=p.length;e<g;e++)l[e]=[];e=0;for(g=p.length;e<g;e++)for(f=n[e],m=0;m<f.length;m++){q=f[m];s=!0;for(v=0;v<p.length;v++)d(q.p,p[v].p)&&(e!==v&&h.push({froms:e,tos:v,hole:m}),s?(s=!1,l[v]. [...]
+t=!0);s&&l[e].push(q)}0<h.length&&(t||(n=l))}t=0;for(e=p.length;t<e;t++)for(l=p[t].s,k.push(l),h=n[t],g=0,f=h.length;g<f;g++)l.holes.push(h[g].h);return k};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.constructor=THREE.Shape;THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry [...]
+THREE.Shape.prototype.getPointsHoles=function(a){for(var b=[],c=0,d=this.holes.length;c<d;c++)b[c]=this.holes[c].getPoints(a);return b};THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.extractAllPoints(a)};THREE.Shape.Utils=THREE.ShapeUtils;THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);
+THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);
+THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve;THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=THREE.ShapeUtils.b2;return new THREE.Vector2(b(a,this.v0.x,this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y))};THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=THREE.CurveUtils.tangentQuadraticBezier;return(new THREE.Vector2(b(a,this.v0.x,this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y))).normalize()};
+THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve;THREE.CubicBezierCurve.prototype.getPoint=function(a){var b=THREE.ShapeUtils.b3;return new THREE.Vector2(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y))};
+THREE.CubicBezierCurve.prototype.getTangent=function(a){var b=THREE.CurveUtils.tangentCubicBezier;return(new THREE.Vector2(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y))).normalize()};THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.constructor=THREE.SplineCurve;
+THREE.SplineCurve.prototype.getPoint=function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0===c?c:c-1],e=b[c],g=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=THREE.CurveUtils.interpolate;return new THREE.Vector2(c(d.x,e.x,g.x,b.x,a),c(d.y,e.y,g.y,b.y,a))};THREE.EllipseCurve=function(a,b,c,d,e,g,f,h){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=g;this.aClockwise=f;this.aRotation=h||0};THREE.EllipseCurve.pro [...]
+THREE.EllipseCurve.prototype.constructor=THREE.EllipseCurve;
+THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);b=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);var c=this.aY+this.yRadius*Math.sin(b);if(0!==this.aRotation){var b=Math.cos(this.aRotation),d=Math.sin(this.aRotation),e=a;a=(e-this.aX)*b-(c-this.aY)*d+this.aX;c=(e-this.aX)*d+(c-this.aY)*b+this.aY}return new THREE.Vector2(a,c)};
+THREE.ArcCurve=function(a,b,c,d,e,g){THREE.EllipseCurve.call(this,a,b,c,c,d,e,g)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype);THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});
+THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b=THREE.ShapeUtils.b2;return new THREE.Vector3(b(a,this.v0.x,this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y),b(a,this.v0.z,this.v1.z,this.v2.z))});
+THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=THREE.ShapeUtils.b3;return new THREE.Vector3(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),b(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z))});
+THREE.SplineCurve3=THREE.Curve.create(function(a){console.warn("THREE.SplineCurve3 will be deprecated. Please use THREE.CatmullRomCurve3");this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],g=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=THREE.CurveUtils.interpolate;return new THREE.Vector3(c(d.x,e.x,g.x,b.x,a),c(d.y,e.y,g.y,b.y,a),c(d.z,e.z,g.z,b.z,a))});
+THREE.CatmullRomCurve3=function(){function a(){}var b=new THREE.Vector3,c=new a,d=new a,e=new a;a.prototype.init=function(a,b,c,d){this.c0=a;this.c1=c;this.c2=-3*a+3*b-2*c-d;this.c3=2*a-2*b+c+d};a.prototype.initNonuniformCatmullRom=function(a,b,c,d,e,m,p){a=((b-a)/e-(c-a)/(e+m)+(c-b)/m)*m;d=((c-b)/m-(d-b)/(m+p)+(d-c)/p)*m;this.init(b,c,a,d)};a.prototype.initCatmullRom=function(a,b,c,d,e){this.init(b,c,e*(c-a),e*(d-b))};a.prototype.calc=function(a){var b=a*a;return this.c0+this.c1*a+this. [...]
+b*a};return THREE.Curve.create(function(a){this.points=a||[]},function(a){var f=this.points,h,l;l=f.length;2>l&&console.log("duh, you need at least 2 points");a*=l-1;h=Math.floor(a);a-=h;0===a&&h===l-1&&(h=l-2,a=1);var k,m,p;0===h?(b.subVectors(f[0],f[1]).add(f[0]),k=b):k=f[h-1];m=f[h];p=f[h+1];h+2<l?f=f[h+2]:(b.subVectors(f[l-1],f[l-2]).add(f[l-2]),f=b);if(void 0===this.type||"centripetal"===this.type||"chordal"===this.type){var n="chordal"===this.type?.5:.25;l=Math.pow(k.distanceToSqua [...]
+h=Math.pow(m.distanceToSquared(p),n);n=Math.pow(p.distanceToSquared(f),n);1E-4>h&&(h=1);1E-4>l&&(l=h);1E-4>n&&(n=h);c.initNonuniformCatmullRom(k.x,m.x,p.x,f.x,l,h,n);d.initNonuniformCatmullRom(k.y,m.y,p.y,f.y,l,h,n);e.initNonuniformCatmullRom(k.z,m.z,p.z,f.z,l,h,n)}else"catmullrom"===this.type&&(l=void 0!==this.tension?this.tension:.5,c.initCatmullRom(k.x,m.x,p.x,f.x,l),d.initCatmullRom(k.y,m.y,p.y,f.y,l),e.initCatmullRom(k.z,m.z,p.z,f.z,l));return new THREE.Vector3(c.calc(a),d.calc(a),e [...]
+THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-0;var c=Math.floor(a);a-=c;var c=c+(0<c?0:(Math.floor(Math.abs(c)/b.length)+1)*b.length),d=b[(c-1)%b.length],e=b[c%b.length],g=b[(c+1)%b.length],b=b[(c+2)%b.length],c=THREE.CurveUtils.interpolate;return new THREE.Vector3(c(d.x,e.x,g.x,b.x,a),c(d.y,e.y,g.y,b.y,a),c(d.z,e.z,g.z,b.z,a))});
+THREE.BoxGeometry=function(a,b,c,d,e,g){function f(a,b,c,d,e,f,g,t){var v,u=h.widthSegments,w=h.heightSegments,D=e/2,x=f/2,B=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)v="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)v="y",w=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)v="x",u=h.depthSegments;var y=u+1,z=w+1,A=e/u,J=f/w,F=new THREE.Vector3;F[v]=0<g?1:-1;for(e=0;e<z;e++)for(f=0;f<y;f++){var C=new THREE.Vector3;C[a]=(f*A-D)*c;C[b]=(e*J-x)*d;C[v]=g;h.vertices.push [...]
+0;e<w;e++)for(f=0;f<u;f++)x=f+y*e,a=f+y*(e+1),b=f+1+y*(e+1),c=f+1+y*e,d=new THREE.Vector2(f/u,1-e/w),g=new THREE.Vector2(f/u,1-(e+1)/w),v=new THREE.Vector2((f+1)/u,1-(e+1)/w),D=new THREE.Vector2((f+1)/u,1-e/w),x=new THREE.Face3(x+B,a+B,c+B),x.normal.copy(F),x.vertexNormals.push(F.clone(),F.clone(),F.clone()),x.materialIndex=t,h.faces.push(x),h.faceVertexUvs[0].push([d,g,D]),x=new THREE.Face3(a+B,b+B,c+B),x.normal.copy(F),x.vertexNormals.push(F.clone(),F.clone(),F.clone()),x.materialIndex [...]
+h.faceVertexUvs[0].push([g.clone(),v,D.clone()])}THREE.Geometry.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:g};this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments=g||1;var h=this;d=a/2;e=b/2;g=c/2;f("z","y",-1,-1,c,b,d,0);f("z","y",1,-1,c,b,-d,1);f("x","z",1,1,a,c,e,2);f("x","z",1,-1,a,c,-e,3);f("x","y",1,-1,a,b,g,4);f("x","y",-1,-1,a,b,-g,5);this.mergeVertices()};THREE.BoxGeometry.prototype=O [...]
+THREE.BoxGeometry.prototype.constructor=THREE.BoxGeometry;THREE.BoxGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.BoxGeometry(a.width,a.height,a.depth,a.widthSegments,a.heightSegments,a.depthSegments)};THREE.CubeGeometry=THREE.BoxGeometry;THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="CircleGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};this.fromBufferGeometry(new THREE.CircleBufferGeometry(a,b,c,d))};
+THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CircleGeometry.prototype.constructor=THREE.CircleGeometry;THREE.CircleGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.CircleGeometry(a.radius,a.segments,a.thetaStart,a.thetaLength)};
+THREE.CircleBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="CircleBufferGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e=b+2,g=new Float32Array(3*e),f=new Float32Array(3*e),e=new Float32Array(2*e);f[2]=1;e[0]=.5;e[1]=.5;for(var h=0,l=3,k=2;h<=b;h++,l+=3,k+=2){var m=c+h/b*d;g[l]=a*Math.cos(m);g[l+1]=a*Math.sin(m);f[l+2]=1;e[k]=(g[l]/a+1)/2;e[k+1]=(g[l+ [...]
+[];for(l=1;l<=b;l++)c.push(l,l+1,0);this.setIndex(new THREE.BufferAttribute(new Uint16Array(c),1));this.addAttribute("position",new THREE.BufferAttribute(g,3));this.addAttribute("normal",new THREE.BufferAttribute(f,3));this.addAttribute("uv",new THREE.BufferAttribute(e,2));this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.CircleBufferGeometry.prototype.constructor=THREE.CircleBufferGeometry;
+THREE.CircleBufferGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.CircleBufferGeometry(a.radius,a.segments,a.thetaStart,a.thetaLength)};
+THREE.CylinderGeometry=function(a,b,c,d,e,g,f,h){THREE.Geometry.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:g,thetaStart:f,thetaLength:h};a=void 0!==a?a:20;b=void 0!==b?b:20;c=void 0!==c?c:100;d=d||8;e=e||1;g=void 0!==g?g:!1;f=void 0!==f?f:0;h=void 0!==h?h:2*Math.PI;var l=c/2,k,m,p=[],n=[];for(m=0;m<=e;m++){var q=[],s=[],t=m/e,v=t*(b-a)+a;for(k=0;k<=d;k++){var u=k/d,w=new THREE.Vector3;w.x=v*Math [...]
+f);w.y=-t*c+l;w.z=v*Math.cos(u*h+f);this.vertices.push(w);q.push(this.vertices.length-1);s.push(new THREE.Vector2(u,1-t))}p.push(q);n.push(s)}c=(b-a)/c;for(k=0;k<d;k++)for(0!==a?(f=this.vertices[p[0][k]].clone(),h=this.vertices[p[0][k+1]].clone()):(f=this.vertices[p[1][k]].clone(),h=this.vertices[p[1][k+1]].clone()),f.setY(Math.sqrt(f.x*f.x+f.z*f.z)*c).normalize(),h.setY(Math.sqrt(h.x*h.x+h.z*h.z)*c).normalize(),m=0;m<e;m++){var q=p[m][k],s=p[m+1][k],t=p[m+1][k+1],v=p[m][k+1],u=f.clone() [...]
+D=h.clone(),x=h.clone(),B=n[m][k].clone(),y=n[m+1][k].clone(),z=n[m+1][k+1].clone(),A=n[m][k+1].clone();this.faces.push(new THREE.Face3(q,s,v,[u,w,x]));this.faceVertexUvs[0].push([B,y,A]);this.faces.push(new THREE.Face3(s,t,v,[w.clone(),D,x.clone()]));this.faceVertexUvs[0].push([y.clone(),z,A.clone()])}if(!1===g&&0<a)for(this.vertices.push(new THREE.Vector3(0,l,0)),k=0;k<d;k++)q=p[0][k],s=p[0][k+1],t=this.vertices.length-1,u=new THREE.Vector3(0,1,0),w=new THREE.Vector3(0,1,0),D=new THREE [...]
+1,0),B=n[0][k].clone(),y=n[0][k+1].clone(),z=new THREE.Vector2(y.x,0),this.faces.push(new THREE.Face3(q,s,t,[u,w,D],void 0,1)),this.faceVertexUvs[0].push([B,y,z]);if(!1===g&&0<b)for(this.vertices.push(new THREE.Vector3(0,-l,0)),k=0;k<d;k++)q=p[e][k+1],s=p[e][k],t=this.vertices.length-1,u=new THREE.Vector3(0,-1,0),w=new THREE.Vector3(0,-1,0),D=new THREE.Vector3(0,-1,0),B=n[e][k+1].clone(),y=n[e][k].clone(),z=new THREE.Vector2(y.x,1),this.faces.push(new THREE.Face3(q,s,t,[u,w,D],void 0,2)) [...]
+y,z]);this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;THREE.CylinderGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.CylinderGeometry(a.radiusTop,a.radiusBottom,a.height,a.radialSegments,a.heightSegments,a.openEnded,a.thetaStart,a.thetaLength)};
+THREE.EdgesGeometry=function(a,b){function c(a,b){return a-b}THREE.BufferGeometry.call(this);var d=Math.cos(THREE.Math.degToRad(void 0!==b?b:1)),e=[0,0],g={},f=["a","b","c"],h;a instanceof THREE.BufferGeometry?(h=new THREE.Geometry,h.fromBufferGeometry(a)):h=a.clone();h.mergeVertices();h.computeFaceNormals();var l=h.vertices;h=h.faces;for(var k=0,m=h.length;k<m;k++)for(var p=h[k],n=0;3>n;n++){e[0]=p[f[n]];e[1]=p[f[(n+1)%3]];e.sort(c);var q=e.toString();void 0===g[q]?g[q]={vert1:e[0],vert [...]
+face2:void 0}:g[q].face2=k}e=[];for(q in g)if(f=g[q],void 0===f.face2||h[f.face1].normal.dot(h[f.face2].normal)<=d)k=l[f.vert1],e.push(k.x),e.push(k.y),e.push(k.z),k=l[f.vert2],e.push(k.x),e.push(k.y),e.push(k.z);this.addAttribute("position",new THREE.BufferAttribute(new Float32Array(e),3))};THREE.EdgesGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.EdgesGeometry.prototype.constructor=THREE.EdgesGeometry;
+THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),this.type="ExtrudeGeometry",a=Array.isArray(a)?a:[a],this.addShapeList(a,b),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry;THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)};
+THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.error("THREE.ExtrudeGeometry: vec does not exist");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=1,d=a.x-b.x,e=a.y-b.y,f=c.x-a.x,g=c.y-a.y,h=d*d+e*e;if(Math.abs(d*g-e*f)>Number.EPSILON){var k=Math.sqrt(h),l=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;f=((c.x-g/l-h)*g-(c.y+f/l-b)*f)/(d*g-e*f);c=h+d*f-a.x;a=b+e*f-a.y;d=c*c+a*a;if(2>=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,d [...]
+f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(G=a.length;0<=--G;){c=G;d=G-1;0>d&&(d=a.length-1);for(var e=0,f=q+2*m,e=0;e<f;e++){var g=T*e,h=T*(e+1),k=b+c+g,g=b+d+g,l=b+d+h,h=b+c+h,k=k+F,g=g+F,l=l+F,h=h+F;J.faces.push(new THREE.Face3(k,g,h,null,null,1));J.faces.push(new THREE.Face3(g,l,h,null,null,1));k=u.generateS [...]
+k,g,l,h);J.faceVertexUvs[0].push([k[0],k[1],k[3]]);J.faceVertexUvs[0].push([k[1],k[2],k[3]])}}}function g(a,b,c){J.vertices.push(new THREE.Vector3(a,b,c))}function f(a,b,c){a+=F;b+=F;c+=F;J.faces.push(new THREE.Face3(a,b,c,null,null,0));a=u.generateTopUV(J,a,b,c);J.faceVertexUvs[0].push(a)}var h=void 0!==b.amount?b.amount:100,l=void 0!==b.bevelThickness?b.bevelThickness:6,k=void 0!==b.bevelSize?b.bevelSize:l-2,m=void 0!==b.bevelSegments?b.bevelSegments:3,p=void 0!==b.bevelEnabled?b.bevel [...]
+n=void 0!==b.curveSegments?b.curveSegments:12,q=void 0!==b.steps?b.steps:1,s=b.extrudePath,t,v=!1,u=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,w,D,x,B;s&&(t=s.getSpacedPoints(q),v=!0,p=!1,w=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(s,q,!1),D=new THREE.Vector3,x=new THREE.Vector3,B=new THREE.Vector3);p||(k=l=m=0);var y,z,A,J=this,F=this.vertices.length,s=a.extractPoints(n),n=s.shape,C=s.holes;if(s=!THREE.ShapeUtils.isClockWise(n)){n=n. [...]
+z=0;for(A=C.length;z<A;z++)y=C[z],THREE.ShapeUtils.isClockWise(y)&&(C[z]=y.reverse());s=!1}var N=THREE.ShapeUtils.triangulateShape(n,C),L=n;z=0;for(A=C.length;z<A;z++)y=C[z],n=n.concat(y);var Q,M,K,E,O,T=n.length,H,R=N.length,s=[],G=0;K=L.length;Q=K-1;for(M=G+1;G<K;G++,Q++,M++)Q===K&&(Q=0),M===K&&(M=0),s[G]=d(L[G],L[Q],L[M]);var ia=[],U,X=s.concat();z=0;for(A=C.length;z<A;z++){y=C[z];U=[];G=0;K=y.length;Q=K-1;for(M=G+1;G<K;G++,Q++,M++)Q===K&&(Q=0),M===K&&(M=0),U[G]=d(y[G],y[Q],y[M]);ia.p [...]
+X.concat(U)}for(Q=0;Q<m;Q++){K=Q/m;E=l*(1-K);M=k*Math.sin(K*Math.PI/2);G=0;for(K=L.length;G<K;G++)O=c(L[G],s[G],M),g(O.x,O.y,-E);z=0;for(A=C.length;z<A;z++)for(y=C[z],U=ia[z],G=0,K=y.length;G<K;G++)O=c(y[G],U[G],M),g(O.x,O.y,-E)}M=k;for(G=0;G<T;G++)O=p?c(n[G],X[G],M):n[G],v?(x.copy(w.normals[0]).multiplyScalar(O.x),D.copy(w.binormals[0]).multiplyScalar(O.y),B.copy(t[0]).add(x).add(D),g(B.x,B.y,B.z)):g(O.x,O.y,0);for(K=1;K<=q;K++)for(G=0;G<T;G++)O=p?c(n[G],X[G],M):n[G],v?(x.copy(w.normals [...]
+D.copy(w.binormals[K]).multiplyScalar(O.y),B.copy(t[K]).add(x).add(D),g(B.x,B.y,B.z)):g(O.x,O.y,h/q*K);for(Q=m-1;0<=Q;Q--){K=Q/m;E=l*(1-K);M=k*Math.sin(K*Math.PI/2);G=0;for(K=L.length;G<K;G++)O=c(L[G],s[G],M),g(O.x,O.y,h+E);z=0;for(A=C.length;z<A;z++)for(y=C[z],U=ia[z],G=0,K=y.length;G<K;G++)O=c(y[G],U[G],M),v?g(O.x,O.y+t[q-1].y,t[q-1].x+E):g(O.x,O.y,h+E)}(function(){if(p){var a;a=0*T;for(G=0;G<R;G++)H=N[G],f(H[2]+a,H[1]+a,H[0]+a);a=q+2*m;a*=T;for(G=0;G<R;G++)H=N[G],f(H[0]+a,H[1]+a,H[2]+ [...]
+0;G<R;G++)H=N[G],f(H[2],H[1],H[0]);for(G=0;G<R;G++)H=N[G],f(H[0]+T*q,H[1]+T*q,H[2]+T*q)}})();(function(){var a=0;e(L,a);a+=L.length;z=0;for(A=C.length;z<A;z++)y=C[z],e(y,a),a+=y.length})()};
+THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d){a=a.vertices;b=a[b];c=a[c];d=a[d];return[new THREE.Vector2(b.x,b.y),new THREE.Vector2(c.x,c.y),new THREE.Vector2(d.x,d.y)]},generateSideWallUV:function(a,b,c,d,e){a=a.vertices;b=a[b];c=a[c];d=a[d];e=a[e];return.01>Math.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.V [...]
+1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===Array.isArray(a)&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.constructor=THREE.ShapeGeometry;THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this};
+THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,g,f,h=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var l=e.shape,k=e.holes;if(!THREE.ShapeUtils.isClockWise(l))for(l=l.reverse(),e=0,g=k.length;e<g;e++)f=k[e],THREE.ShapeUtils.isClockWise(f)&&(k[e]=f.reverse());var m=THREE.ShapeUtils.triangulateShape(l,k);e=0;for(g=k.length;e<g;e++)f [...]
+k=l.length;g=m.length;for(e=0;e<k;e++)f=l[e],this.vertices.push(new THREE.Vector3(f.x,f.y,0));for(e=0;e<g;e++)k=m[e],l=k[0]+h,f=k[1]+h,k=k[2]+h,this.faces.push(new THREE.Face3(l,f,k,null,null,c)),this.faceVertexUvs[0].push(d.generateTopUV(this,l,f,k))};
+THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="LatheGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};b=b||12;c=c||0;d=d||2*Math.PI;for(var e=1/(a.length-1),g=1/b,f=0,h=b;f<=h;f++)for(var l=c+f*g*d,k=Math.cos(l),m=Math.sin(l),l=0,p=a.length;l<p;l++){var n=a[l],q=new THREE.Vector3;q.x=k*n.x-m*n.y;q.y=m*n.x+k*n.y;q.z=n.z;this.vertices.push(q)}c=a.length;f=0;for(h=b;f<h;f++)for(l=0,p=a.length-1;l<p;l++){b=m=l+c*f;d=m+c;var k=m+1+c,m=m+1,n=f*g [...]
+n+g,t=q+e;this.faces.push(new THREE.Face3(b,d,m));this.faceVertexUvs[0].push([new THREE.Vector2(n,q),new THREE.Vector2(s,q),new THREE.Vector2(n,t)]);this.faces.push(new THREE.Face3(d,k,m));this.faceVertexUvs[0].push([new THREE.Vector2(s,q),new THREE.Vector2(s,t),new THREE.Vector2(n,t)])}this.mergeVertices();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.LatheGeometry.prototype.constructor=THREE.LatheGeometry;
+THREE.PlaneGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="PlaneGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};this.fromBufferGeometry(new THREE.PlaneBufferGeometry(a,b,c,d))};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry.prototype.constructor=THREE.PlaneGeometry;THREE.PlaneGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.PlaneGeometry(a.width,a.height,a.widthSegments,a.he [...]
+THREE.PlaneBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="PlaneBufferGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};var e=a/2,g=b/2;c=Math.floor(c)||1;d=Math.floor(d)||1;var f=c+1,h=d+1,l=a/c,k=b/d;b=new Float32Array(f*h*3);a=new Float32Array(f*h*3);for(var m=new Float32Array(f*h*2),p=0,n=0,q=0;q<h;q++)for(var s=q*k-g,t=0;t<f;t++)b[p]=t*l-e,b[p+1]=-s,a[p+2]=1,m[n]=t/c,m[n+1]=1-q/d,p+=3,n+=2;p=0;e=new (65535<b.length/3?Uint32Arra [...]
+d*6);for(q=0;q<d;q++)for(t=0;t<c;t++)g=t+f*(q+1),h=t+1+f*(q+1),l=t+1+f*q,e[p]=t+f*q,e[p+1]=g,e[p+2]=l,e[p+3]=g,e[p+4]=h,e[p+5]=l,p+=6;this.setIndex(new THREE.BufferAttribute(e,1));this.addAttribute("position",new THREE.BufferAttribute(b,3));this.addAttribute("normal",new THREE.BufferAttribute(a,3));this.addAttribute("uv",new THREE.BufferAttribute(m,2))};THREE.PlaneBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.PlaneBufferGeometry.prototype.constructor=THREE. [...]
+THREE.PlaneBufferGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.PlaneBufferGeometry(a.width,a.height,a.widthSegments,a.heightSegments)};
+THREE.RingGeometry=function(a,b,c,d,e,g){THREE.Geometry.call(this);this.type="RingGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:g};a=a||0;b=b||50;e=void 0!==e?e:0;g=void 0!==g?g:2*Math.PI;c=void 0!==c?Math.max(3,c):8;d=void 0!==d?Math.max(1,d):8;var f,h=[],l=a,k=(b-a)/d;for(a=0;a<d+1;a++){for(f=0;f<c+1;f++){var m=new THREE.Vector3,p=e+f/c*g;m.x=l*Math.cos(p);m.y=l*Math.sin(p);this.vertices.push(m);h.push(new THREE.Vector2((m [...]
+(m.y/b+1)/2))}l+=k}b=new THREE.Vector3(0,0,1);for(a=0;a<d;a++)for(e=a*(c+1),f=0;f<c;f++)g=p=f+e,k=p+c+1,m=p+c+2,this.faces.push(new THREE.Face3(g,k,m,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[g].clone(),h[k].clone(),h[m].clone()]),g=p,k=p+c+2,m=p+1,this.faces.push(new THREE.Face3(g,k,m,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[g].clone(),h[k].clone(),h[m].clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,l)};
+THREE.RingGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.RingGeometry.prototype.constructor=THREE.RingGeometry;THREE.RingGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.RingGeometry(a.innerRadius,a.outerRadius,a.thetaSegments,a.phiSegments,a.thetaStart,a.thetaLength)};
+THREE.SphereGeometry=function(a,b,c,d,e,g,f){THREE.Geometry.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:g,thetaLength:f};this.fromBufferGeometry(new THREE.SphereBufferGeometry(a,b,c,d,e,g,f))};THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;
+THREE.SphereGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.SphereGeometry(a.radius,a.widthSegments,a.heightSegments,a.phiStart,a.phiLength,a.thetaStart,a.thetaLength)};
+THREE.SphereBufferGeometry=function(a,b,c,d,e,g,f){THREE.BufferGeometry.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:g,thetaLength:f};a=a||50;b=Math.max(3,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;g=void 0!==g?g:0;f=void 0!==f?f:Math.PI;for(var h=g+f,l=(b+1)*(c+1),k=new THREE.BufferAttribute(new Float32Array(3*l),3),m=new THREE.BufferAttribute(new F [...]
+l),3),l=new THREE.BufferAttribute(new Float32Array(2*l),2),p=0,n=[],q=new THREE.Vector3,s=0;s<=c;s++){for(var t=[],v=s/c,u=0;u<=b;u++){var w=u/b,D=-a*Math.cos(d+w*e)*Math.sin(g+v*f),x=a*Math.cos(g+v*f),B=a*Math.sin(d+w*e)*Math.sin(g+v*f);q.set(D,x,B).normalize();k.setXYZ(p,D,x,B);m.setXYZ(p,q.x,q.y,q.z);l.setXY(p,w,1-v);t.push(p);p++}n.push(t)}d=[];for(s=0;s<c;s++)for(u=0;u<b;u++)e=n[s][u+1],f=n[s][u],p=n[s+1][u],q=n[s+1][u+1],(0!==s||0<g)&&d.push(e,f,q),(s!==c-1||h<Math.PI)&&d.push(f,p, [...]
+k.count?THREE.Uint32Attribute:THREE.Uint16Attribute)(d,1));this.addAttribute("position",k);this.addAttribute("normal",m);this.addAttribute("uv",l);this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.SphereBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.SphereBufferGeometry.prototype.constructor=THREE.SphereBufferGeometry;
+THREE.SphereBufferGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.SphereBufferGeometry(a.radius,a.widthSegments,a.heightSegments,a.phiStart,a.phiLength,a.thetaStart,a.thetaLength)};
+THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.type="TorusGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};a=a||100;b=b||40;c=c||8;d=d||6;e=e||2*Math.PI;for(var g=new THREE.Vector3,f=[],h=[],l=0;l<=c;l++)for(var k=0;k<=d;k++){var m=k/d*e,p=l/c*Math.PI*2;g.x=a*Math.cos(m);g.y=a*Math.sin(m);var n=new THREE.Vector3;n.x=(a+b*Math.cos(p))*Math.cos(m);n.y=(a+b*Math.cos(p))*Math.sin(m);n.z=b*Math.sin(p);this.vertices.push(n);f.push(new [...]
+d,l/c));h.push(n.clone().sub(g).normalize())}for(l=1;l<=c;l++)for(k=1;k<=d;k++)a=(d+1)*l+k-1,b=(d+1)*(l-1)+k-1,e=(d+1)*(l-1)+k,g=(d+1)*l+k,m=new THREE.Face3(a,b,g,[h[a].clone(),h[b].clone(),h[g].clone()]),this.faces.push(m),this.faceVertexUvs[0].push([f[a].clone(),f[b].clone(),f[g].clone()]),m=new THREE.Face3(b,e,g,[h[b].clone(),h[e].clone(),h[g].clone()]),this.faces.push(m),this.faceVertexUvs[0].push([f[b].clone(),f[e].clone(),f[g].clone()]);this.computeFaceNormals()};
+THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry;THREE.TorusGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.TorusGeometry(a.radius,a.tube,a.radialSegments,a.tubularSegments,a.arc)};
+THREE.TorusKnotGeometry=function(a,b,c,d,e,g,f){function h(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a);a*=b/c;b=Math.cos(a);f*=d*(2+b)*.5;g=d*(2+b)*g*.5;d=e*d*Math.sin(a)*.5;return new THREE.Vector3(f,g,d)}THREE.Geometry.call(this);this.type="TorusKnotGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,p:e,q:g,heightScale:f};a=a||100;b=b||40;c=c||64;d=d||8;e=e||2;g=g||3;f=f||1;for(var l=Array(c),k=new THREE.Vector3,m=new THREE.Vector3,p=new THREE.Vector3,n=0;n<c; [...]
+Array(d);var q=n/c*2*e*Math.PI,s=h(q,g,e,a,f),q=h(q+.01,g,e,a,f);k.subVectors(q,s);m.addVectors(q,s);p.crossVectors(k,m);m.crossVectors(p,k);p.normalize();m.normalize();for(q=0;q<d;++q){var t=q/d*2*Math.PI,v=-b*Math.cos(t),t=b*Math.sin(t),u=new THREE.Vector3;u.x=s.x+v*m.x+t*p.x;u.y=s.y+v*m.y+t*p.y;u.z=s.z+v*m.z+t*p.z;l[n][q]=this.vertices.push(u)-1}}for(n=0;n<c;++n)for(q=0;q<d;++q)e=(n+1)%c,g=(q+1)%d,a=l[n][q],b=l[e][q],e=l[e][g],g=l[n][g],f=new THREE.Vector2(n/c,q/d),k=new THREE.Vector2 [...]
+q/d),m=new THREE.Vector2((n+1)/c,(q+1)/d),p=new THREE.Vector2(n/c,(q+1)/d),this.faces.push(new THREE.Face3(a,b,g)),this.faceVertexUvs[0].push([f,k,p]),this.faces.push(new THREE.Face3(b,e,g)),this.faceVertexUvs[0].push([k.clone(),m,p.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry.prototype.constructor=THREE.TorusKnotGeometry;
+THREE.TorusKnotGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.TorusKnotGeometry(a.radius,a.tube,a.radialSegments,a.tubularSegments,a.p,a.q,a.heightScale)};
+THREE.TubeGeometry=function(a,b,c,d,e,g){THREE.Geometry.call(this);this.type="TubeGeometry";this.parameters={path:a,segments:b,radius:c,radialSegments:d,closed:e,taper:g};b=b||64;c=c||1;d=d||8;e=e||!1;g=g||THREE.TubeGeometry.NoTaper;var f=[],h,l,k=b+1,m,p,n,q,s,t=new THREE.Vector3,v,u,w;v=new THREE.TubeGeometry.FrenetFrames(a,b,e);u=v.normals;w=v.binormals;this.tangents=v.tangents;this.normals=u;this.binormals=w;for(v=0;v<k;v++)for(f[v]=[],m=v/(k-1),s=a.getPointAt(m),h=u[v],l=w[v],n=c*g( [...]
+d;m++)p=m/d*2*Math.PI,q=-n*Math.cos(p),p=n*Math.sin(p),t.copy(s),t.x+=q*h.x+p*l.x,t.y+=q*h.y+p*l.y,t.z+=q*h.z+p*l.z,f[v][m]=this.vertices.push(new THREE.Vector3(t.x,t.y,t.z))-1;for(v=0;v<b;v++)for(m=0;m<d;m++)g=e?(v+1)%b:v+1,k=(m+1)%d,a=f[v][m],c=f[g][m],g=f[g][k],k=f[v][k],t=new THREE.Vector2(v/b,m/d),u=new THREE.Vector2((v+1)/b,m/d),w=new THREE.Vector2((v+1)/b,(m+1)/d),h=new THREE.Vector2(v/b,(m+1)/d),this.faces.push(new THREE.Face3(a,c,k)),this.faceVertexUvs[0].push([t,u,h]),this.face [...]
+g,k)),this.faceVertexUvs[0].push([u.clone(),w,h.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry.prototype.constructor=THREE.TubeGeometry;THREE.TubeGeometry.prototype.clone=function(){return new this.constructor(this.parameters.path,this.parameters.segments,this.parameters.radius,this.parameters.radialSegments,this.parameters.closed,this.parameters.taper)};THREE.TubeGeometry.NoTaper=fu [...]
+THREE.TubeGeometry.SinusoidalTaper=function(a){return Math.sin(Math.PI*a)};
+THREE.TubeGeometry.FrenetFrames=function(a,b,c){var d=new THREE.Vector3,e=[],g=[],f=[],h=new THREE.Vector3,l=new THREE.Matrix4;b+=1;var k,m,p;this.tangents=e;this.normals=g;this.binormals=f;for(k=0;k<b;k++)m=k/(b-1),e[k]=a.getTangentAt(m),e[k].normalize();g[0]=new THREE.Vector3;f[0]=new THREE.Vector3;a=Number.MAX_VALUE;k=Math.abs(e[0].x);m=Math.abs(e[0].y);p=Math.abs(e[0].z);k<=a&&(a=k,d.set(1,0,0));m<=a&&(a=m,d.set(0,1,0));p<=a&&d.set(0,0,1);h.crossVectors(e[0],d).normalize();g[0].cross [...]
+h);f[0].crossVectors(e[0],g[0]);for(k=1;k<b;k++)g[k]=g[k-1].clone(),f[k]=f[k-1].clone(),h.crossVectors(e[k-1],e[k]),h.length()>Number.EPSILON&&(h.normalize(),d=Math.acos(THREE.Math.clamp(e[k-1].dot(e[k]),-1,1)),g[k].applyMatrix4(l.makeRotationAxis(h,d))),f[k].crossVectors(e[k],g[k]);if(c)for(d=Math.acos(THREE.Math.clamp(g[0].dot(g[b-1]),-1,1)),d/=b-1,0<e[0].dot(h.crossVectors(g[0],g[b-1]))&&(d=-d),k=1;k<b;k++)g[k].applyMatrix4(l.makeRotationAxis(e[k],d*k)),f[k].crossVectors(e[k],g[k])};
+THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=l.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+.5;a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+.5;b.uv=new THREE.Vector2(c,1-a);return b}function g(a,b,c,d){d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()],void 0,d);l.faces.push(d);v.copy(a).add(b).add(c).divideScalar(3);d=Math.atan2(v.z,-v.x);l.faceVertexUvs[0].push([h(a.uv,a,d),h(b.uv,b,d),h(c.uv,c,d [...]
+b){for(var c=Math.pow(2,b),d=e(l.vertices[a.a]),f=e(l.vertices[a.b]),h=e(l.vertices[a.c]),k=[],n=a.materialIndex,m=0;m<=c;m++){k[m]=[];for(var p=e(d.clone().lerp(h,m/c)),q=e(f.clone().lerp(h,m/c)),s=c-m,t=0;t<=s;t++)k[m][t]=0===t&&m===c?p:e(p.clone().lerp(q,t/s))}for(m=0;m<c;m++)for(t=0;t<2*(c-m)-1;t++)d=Math.floor(t/2),0===t%2?g(k[m][d+1],k[m+1][d],k[m][d],n):g(k[m][d+1],k[m+1][d+1],k[m+1][d],n)}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new TH [...]
+2/Math.PI+.5,a.y));return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var l=this,k=0,m=a.length;k<m;k+=3)e(new THREE.Vector3(a[k],a[k+1],a[k+2]));a=this.vertices;for(var p=[],n=k=0,m=b.length;k<m;k+=3,n++){var q=a[b[k]],s=a[b[k+1]],t=a[b[k+2]];p[n]=new THREE.Face3(q.index,s.index,t.index,[q.clone(),s.clone(),t.clone()],void 0,n)}for(var v=new THREE.Vector3,k=0,m=p.length;k<m;k++)f(p[k],d);k= [...]
+m;k++)b=this.faceVertexUvs[0][k],d=b[0].x,a=b[1].x,p=b[2].x,n=Math.max(d,a,p),q=Math.min(d,a,p),.9<n&&.1>q&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>p&&(b[2].x+=1));k=0;for(m=this.vertices.length;k<m;k++)this.vertices[k].multiplyScalar(c);this.mergeVertices();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PolyhedronGeometry.prototype.constructor=THREE.PolyhedronGeometry;
+THREE.PolyhedronGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.PolyhedronGeometry(a.vertices,a.indices,a.radius,a.detail)};
+THREE.DodecahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2,d=1/c;THREE.PolyhedronGeometry.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,1 [...]
+12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b}};THREE.DodecahedronGeometry.prototype=Object.create(THREE.PolyhedronGeometry.prototype);THREE.DodecahedronGeometry.prototype.constructor=THREE.DodecahedronGeometry;THREE.DodecahedronGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.DodecahedronGeometry(a.radius,a.detail)};
+THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b}};THREE.IcosahedronGeometry.prototype=Object.create(THREE.PolyhedronGeometry.prototype);
+THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;THREE.IcosahedronGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.IcosahedronGeometry(a.radius,a.detail)};THREE.OctahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b}};THREE.OctahedronGeometry.prototype=Object.create [...]
+THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry;THREE.OctahedronGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.OctahedronGeometry(a.radius,a.detail)};THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b}};THREE.TetrahedronGeometry.prototype=Object.create(THREE.PolyhedronGeometry.prototype);
+THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry;THREE.TetrahedronGeometry.prototype.clone=function(){var a=this.parameters;return new THREE.TetrahedronGeometry(a.radius,a.detail)};
+THREE.ParametricGeometry=function(a,b,c){THREE.Geometry.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};var d=this.vertices,e=this.faces,g=this.faceVertexUvs[0],f,h,l,k,m=b+1;for(f=0;f<=c;f++)for(k=f/c,h=0;h<=b;h++)l=h/b,l=a(l,k),d.push(l);var p,n,q,s;for(f=0;f<c;f++)for(h=0;h<b;h++)a=f*m+h,d=f*m+h+1,k=(f+1)*m+h+1,l=(f+1)*m+h,p=new THREE.Vector2(h/b,f/c),n=new THREE.Vector2((h+1)/b,f/c),q=new THREE.Vector2((h+1)/b,(f+1)/c),s=new THREE.Vector2(h/b,(f+1 [...]
+d,l)),g.push([p,n,s]),e.push(new THREE.Face3(d,k,l)),g.push([n.clone(),q,s.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry;
+THREE.WireframeGeometry=function(a){function b(a,b){return a-b}THREE.BufferGeometry.call(this);var c=[0,0],d={},e=["a","b","c"];if(a instanceof THREE.Geometry){var g=a.vertices,f=a.faces,h=0,l=new Uint32Array(6*f.length);a=0;for(var k=f.length;a<k;a++)for(var m=f[a],p=0;3>p;p++){c[0]=m[e[p]];c[1]=m[e[(p+1)%3]];c.sort(b);var n=c.toString();void 0===d[n]&&(l[2*h]=c[0],l[2*h+1]=c[1],d[n]=!0,h++)}c=new Float32Array(6*h);a=0;for(k=h;a<k;a++)for(p=0;2>p;p++)d=g[l[2*a+p]],h=6*a+3*p,c[h+0]=d.x,c [...]
+c[h+2]=d.z;this.addAttribute("position",new THREE.BufferAttribute(c,3))}else if(a instanceof THREE.BufferGeometry){if(null!==a.index){k=a.index.array;g=a.attributes.position;e=a.drawcalls;h=0;0===e.length&&a.addGroup(0,k.length);l=new Uint32Array(2*k.length);f=0;for(m=e.length;f<m;++f){a=e[f];p=a.start;n=a.count;a=p;for(var q=p+n;a<q;a+=3)for(p=0;3>p;p++)c[0]=k[a+p],c[1]=k[a+(p+1)%3],c.sort(b),n=c.toString(),void 0===d[n]&&(l[2*h]=c[0],l[2*h+1]=c[1],d[n]=!0,h++)}c=new Float32Array(6*h);a [...]
+h;a<k;a++)for(p=0;2>p;p++)h=6*a+3*p,d=l[2*a+p],c[h+0]=g.getX(d),c[h+1]=g.getY(d),c[h+2]=g.getZ(d)}else for(g=a.attributes.position.array,h=g.length/3,l=h/3,c=new Float32Array(6*h),a=0,k=l;a<k;a++)for(p=0;3>p;p++)h=18*a+6*p,l=9*a+3*p,c[h+0]=g[l],c[h+1]=g[l+1],c[h+2]=g[l+2],d=9*a+(p+1)%3*3,c[h+3]=g[d],c[h+4]=g[d+1],c[h+5]=g[d+2];this.addAttribute("position",new THREE.BufferAttribute(c,3))}};THREE.WireframeGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);
+THREE.WireframeGeometry.prototype.constructor=THREE.WireframeGeometry;THREE.AxisHelper=function(a){a=a||1;var b=new Float32Array([0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a]),c=new Float32Array([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1]);a=new THREE.BufferGeometry;a.addAttribute("position",new THREE.BufferAttribute(b,3));a.addAttribute("color",new THREE.BufferAttribute(c,3));b=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.LineSegments.call(this,a,b)};THREE.AxisHelper.protot [...]
+THREE.AxisHelper.prototype.constructor=THREE.AxisHelper;
+THREE.ArrowHelper=function(){var a=new THREE.Geometry;a.vertices.push(new THREE.Vector3(0,0,0),new THREE.Vector3(0,1,0));var b=new THREE.CylinderGeometry(0,.5,1,5,1);b.translate(0,-.5,0);return function(c,d,e,g,f,h){THREE.Object3D.call(this);void 0===g&&(g=16776960);void 0===e&&(e=1);void 0===f&&(f=.2*e);void 0===h&&(h=.2*f);this.position.copy(d);f<e&&(this.line=new THREE.Line(a,new THREE.LineBasicMaterial({color:g})),this.line.matrixAutoUpdate=!1,this.add(this.line));this.cone=new THREE [...]
+this.cone.matrixAutoUpdate=!1;this.add(this.cone);this.setDirection(c);this.setLength(e,f,h)}}();THREE.ArrowHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.ArrowHelper.prototype.constructor=THREE.ArrowHelper;THREE.ArrowHelper.prototype.setDirection=function(){var a=new THREE.Vector3,b;return function(c){.99999<c.y?this.quaternion.set(0,0,0,1):-.99999>c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();
+THREE.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);b<a&&(this.line.scale.set(1,a-b,1),this.line.updateMatrix());this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};THREE.ArrowHelper.prototype.setColor=function(a){void 0!==this.line&&this.line.material.color.set(a);this.cone.material.color.set(a)};
+THREE.BoxHelper=function(a){var b=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),c=new Float32Array(24),d=new THREE.BufferGeometry;d.setIndex(new THREE.BufferAttribute(b,1));d.addAttribute("position",new THREE.BufferAttribute(c,3));THREE.LineSegments.call(this,d,new THREE.LineBasicMaterial({color:16776960}));void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.BoxHelper.prototype.constructor=THREE.BoxHelper;
+THREE.BoxHelper.prototype.update=function(){var a=new THREE.Box3;return function(b){a.setFromObject(b);if(!a.empty()){b=a.min;var c=a.max,d=this.geometry.attributes.position,e=d.array;e[0]=c.x;e[1]=c.y;e[2]=c.z;e[3]=b.x;e[4]=c.y;e[5]=c.z;e[6]=b.x;e[7]=b.y;e[8]=c.z;e[9]=c.x;e[10]=b.y;e[11]=c.z;e[12]=c.x;e[13]=c.y;e[14]=b.z;e[15]=b.x;e[16]=c.y;e[17]=b.z;e[18]=b.x;e[19]=b.y;e[20]=b.z;e[21]=c.x;e[22]=b.y;e[23]=b.z;d.needsUpdate=!0;this.geometry.computeBoundingSphere()}}}();
+THREE.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.constructor=THREE.BoundingBoxHelper;THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)};
+THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===g[a]&&(g[a]=[]);g[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),g={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n [...]
+b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.LineSegments.call(this,d,e);this.camera=a;this.camera.updateProjectionMatrix();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=g;th [...]
+THREE.CameraHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.CameraHelper.prototype.constructor=THREE.CameraHelper;
+THREE.CameraHelper.prototype.update=function(){function a(a,f,h,l){d.set(f,h,l).unproject(e);a=c[a];if(void 0!==a)for(f=0,h=a.length;f<h;f++)b.vertices[a[f]].copy(d)}var b,c,d=new THREE.Vector3,e=new THREE.Camera;return function(){b=this.geometry;c=this.pointMap;e.projectionMatrix.copy(this.camera.projectionMatrix);a("c",0,0,-1);a("t",0,0,1);a("n1",-1,-1,-1);a("n2",1,-1,-1);a("n3",-1,1,-1);a("n4",1,1,-1);a("f1",-1,-1,1);a("f2",1,-1,1);a("f3",-1,1,1);a("f4",1,1,1);a("u1",.7,1.1,-1);a("u2" [...]
+-1);a("u3",0,2,-1);a("cf1",-1,0,1);a("cf2",1,0,1);a("cf3",0,-1,1);a("cf4",0,1,1);a("cn1",-1,0,-1);a("cn2",1,0,-1);a("cn3",0,-1,-1);a("cn4",0,1,-1);b.verticesNeedUpdate=!0}}();
+THREE.DirectionalLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;b=b||1;var c=new THREE.Geometry;c.vertices.push(new THREE.Vector3(-b,b,0),new THREE.Vector3(b,b,0),new THREE.Vector3(b,-b,0),new THREE.Vector3(-b,-b,0),new THREE.Vector3(-b,b,0));var d=new THREE.LineBasicMaterial({fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.lightPlane=new THREE.Line(c,d);t [...]
+c=new THREE.Geometry;c.vertices.push(new THREE.Vector3,new THREE.Vector3);d=new THREE.LineBasicMaterial({fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine=new THREE.Line(c,d);this.add(this.targetLine);this.update()};THREE.DirectionalLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.DirectionalLightHelper.prototype.constructor=THREE.DirectionalLightHelper;
+THREE.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose();this.lightPlane.material.dispose();this.targetLine.geometry.dispose();this.targetLine.material.dispose()};
+THREE.DirectionalLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);c.subVectors(b,a);this.lightPlane.lookAt(c);this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine.geometry.vertices[1].copy(c);this.targetLine.geometry.verticesNeedUpdate=!0;this.targetLine.materia [...]
+THREE.EdgesHelper=function(a,b,c){b=void 0!==b?b:16777215;THREE.LineSegments.call(this,new THREE.EdgesGeometry(a.geometry,c),new THREE.LineBasicMaterial({color:b}));this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.EdgesHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.EdgesHelper.prototype.constructor=THREE.EdgesHelper;
+THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=0;c=this.object.geometry;c instanceof THREE.Geometry?b=c.faces.length:console.warn("THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.");c=new THREE.BufferGeometry;b=new THREE.Float32Attribute(6*b,3);c.addAttribute("position",b);THREE.LineSegments.call(this,c,new THREE.LineBasicMaterial({color:a,linewidth:d}));this.mat [...]
+!1;this.update()};THREE.FaceNormalsHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.FaceNormalsHelper.prototype.constructor=THREE.FaceNormalsHelper;
+THREE.FaceNormalsHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Matrix3;return function(){this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld);for(var d=this.object.matrixWorld,e=this.geometry.attributes.position,g=this.object.geometry,f=g.vertices,g=g.faces,h=0,l=0,k=g.length;l<k;l++){var m=g[l],p=m.normal;a.copy(f[m.a]).add(f[m.b]).add(f[m.c]).divideScalar(3).applyMatrix4(d);b.copy(p).applyMatrix3(c).normalize().multip [...]
+e.setXYZ(h,a.x,a.y,a.z);h+=1;e.setXYZ(h,b.x,b.y,b.z);h+=1}e.needsUpdate=!0;return this}}();
+THREE.GridHelper=function(a,b){var c=new THREE.Geometry,d=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});this.color1=new THREE.Color(4473924);this.color2=new THREE.Color(8947848);for(var e=-a;e<=a;e+=b){c.vertices.push(new THREE.Vector3(-a,0,e),new THREE.Vector3(a,0,e),new THREE.Vector3(e,0,-a),new THREE.Vector3(e,0,a));var g=0===e?this.color1:this.color2;c.colors.push(g,g,g,g)}THREE.LineSegments.call(this,c,d)};THREE.GridHelper.prototype=Object.create(THREE.LineSegments. [...]
+THREE.GridHelper.prototype.constructor=THREE.GridHelper;THREE.GridHelper.prototype.setColors=function(a,b){this.color1.set(a);this.color2.set(b);this.geometry.colorsNeedUpdate=!0};
+THREE.HemisphereLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.colors=[new THREE.Color,new THREE.Color];var c=new THREE.SphereGeometry(b,4,2);c.rotateX(-Math.PI/2);for(var d=0;8>d;d++)c.faces[d].color=this.colors[4>d?0:1];d=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(c,d);this.add(this.lightSphere);this.update()};
+THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.constructor=THREE.HemisphereLightHelper;THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()};
+THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}();
+THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.constructor=THREE.PointLightHelper;
+THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()};THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)};
+THREE.SkeletonHelper=function(a){this.bones=this.getBoneList(a);for(var b=new THREE.Geometry,c=0;c<this.bones.length;c++)this.bones[c].parent instanceof THREE.Bone&&(b.vertices.push(new THREE.Vector3),b.vertices.push(new THREE.Vector3),b.colors.push(new THREE.Color(0,0,1)),b.colors.push(new THREE.Color(0,1,0)));b.dynamic=!0;c=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors,depthTest:!1,depthWrite:!1,transparent:!0});THREE.LineSegments.call(this,b,c);this.root=a;this.matrix=a [...]
+this.matrixAutoUpdate=!1;this.update()};THREE.SkeletonHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.SkeletonHelper.prototype.constructor=THREE.SkeletonHelper;THREE.SkeletonHelper.prototype.getBoneList=function(a){var b=[];a instanceof THREE.Bone&&b.push(a);for(var c=0;c<a.children.length;c++)b.push.apply(b,this.getBoneList(a.children[c]));return b};
+THREE.SkeletonHelper.prototype.update=function(){for(var a=this.geometry,b=(new THREE.Matrix4).getInverse(this.root.matrixWorld),c=new THREE.Matrix4,d=0,e=0;e<this.bones.length;e++){var g=this.bones[e];g.parent instanceof THREE.Bone&&(c.multiplyMatrices(b,g.matrixWorld),a.vertices[d].setFromMatrixPosition(c),c.multiplyMatrices(b,g.parent.matrixWorld),a.vertices[d+1].setFromMatrixPosition(c),d+=2)}a.verticesNeedUpdate=!0;a.computeBoundingSphere()};
+THREE.SpotLightHelper=function(a){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;a=new THREE.CylinderGeometry(0,1,1,8,1,!0);a.translate(0,-.5,0);a.rotateX(-Math.PI/2);var b=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new THREE.Mesh(a,b);this.add(this.cone);this.update()};THREE.SpotLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.SpotLightHelper.prototype.constructor=THREE.SpotLig [...]
+THREE.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()};THREE.SpotLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){var c=this.light.distance?this.light.distance:1E4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c);a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);this.cone.lookAt(b.sub(a));this.cone.material.color.copy(th [...]
+THREE.VertexNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16711680;d=void 0!==d?d:1;b=0;c=this.object.geometry;c instanceof THREE.Geometry?b=3*c.faces.length:c instanceof THREE.BufferGeometry&&(b=c.attributes.normal.count);c=new THREE.BufferGeometry;b=new THREE.Float32Attribute(6*b,3);c.addAttribute("position",b);THREE.LineSegments.call(this,c,new THREE.LineBasicMaterial({color:a,linewidth:d}));this.matrixAutoUpdate=!1;this.update()};
+THREE.VertexNormalsHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.VertexNormalsHelper.prototype.constructor=THREE.VertexNormalsHelper;
+THREE.VertexNormalsHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Matrix3;return function(){var d=["a","b","c"];this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld);var e=this.object.matrixWorld,g=this.geometry.attributes.position,f=this.object.geometry;if(f instanceof THREE.Geometry)for(var h=f.vertices,l=f.faces,k=f=0,m=l.length;k<m;k++)for(var p=l[k],n=0,q=p.vertexNormals.length;n<q;n++){var s=p.vertexNormals[n];a.cop [...]
+b.copy(s).applyMatrix3(c).normalize().multiplyScalar(this.size).add(a);g.setXYZ(f,a.x,a.y,a.z);f+=1;g.setXYZ(f,b.x,b.y,b.z);f+=1}else if(f instanceof THREE.BufferGeometry)for(d=f.attributes.position,h=f.attributes.normal,n=f=0,q=d.count;n<q;n++)a.set(d.getX(n),d.getY(n),d.getZ(n)).applyMatrix4(e),b.set(h.getX(n),h.getY(n),h.getZ(n)),b.applyMatrix3(c).normalize().multiplyScalar(this.size).add(a),g.setXYZ(f,a.x,a.y,a.z),f+=1,g.setXYZ(f,b.x,b.y,b.z),f+=1;g.needsUpdate=!0;return this}}();
+THREE.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215;THREE.LineSegments.call(this,new THREE.WireframeGeometry(a.geometry),new THREE.LineBasicMaterial({color:c}));this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.LineSegments.prototype);THREE.WireframeHelper.prototype.constructor=THREE.WireframeHelper;THREE.ImmediateRenderObject=function(a){THREE.Object3D.call(this);this.material=a;this.render=function(a){}};
+THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.ImmediateRenderObject.prototype.constructor=THREE.ImmediateRenderObject;THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.MorphBlendMesh.prototype.construc [...]
+THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={start:b,end:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)};
+THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,g=0,f=e.morphTargets.length;g<f;g++){var h=e.morphTargets[g].name.match(b);if(h&&1<h.length){var l=h[1];d[l]||(d[l]={start:Infinity,end:-Infinity});h=d[l];g<h.start&&(h.start=g);g>h.end&&(h.end=g);c||(c=l)}}for(l in d)h=d[l],this.createAnimation(l,h.start,h.end,a);this.firstAnimation=c};
+THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)};
+THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b};
+THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("THREE.MorphBlendMesh: animation["+a+"] undefined in .playAnimation()")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1};
+THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;b<c;b++){var d=this.animationsList[b];if(d.active){var e=d.duration/d.length;d.time+=d.direction*a;if(d.mirroredLoop){if(d.time>d.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var g=d.start+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),f=d.wei [...]
+(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*f,this.morphTargetInfluences[g]=0,d.lastFrame=d.currentFrame,d.currentFrame=g);e=d.time%e/e;d.directionBackwards&&(e=1-e);d.currentFrame!==d.lastFrame?(this.morphTargetInfluences[d.currentFrame]=e*f,this.morphTargetInfluences[d.lastFrame]=(1-e)*f):this.morphTargetInfluences[d.currentFrame]=f}}};
diff --git a/emperor/support_files/vendor/js/underscore-min.js b/emperor/support_files/vendor/js/underscore-min.js
new file mode 100644
index 0000000..f01025b
--- /dev/null
+++ b/emperor/support_files/vendor/js/underscore-min.js
@@ -0,0 +1,6 @@
+//     Underscore.js 1.8.3
+//     http://underscorejs.org
+//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Underscore may be freely distributed under the MIT license.
+(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a [...]
+//# sourceMappingURL=underscore-min.map
\ No newline at end of file
diff --git a/examples/build.py b/examples/build.py
new file mode 100755
index 0000000..4551d0c
--- /dev/null
+++ b/examples/build.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+"""
+build.py: create an emperor plot with N random data samples by default N=10 but
+you can change this value when calling from the command line, for example
+to generate a plot with 111 samples do:
+
+    ./build.py 111
+
+Note that you will need jinja2 installed, and to execute the program from
+within the examples folder.
+"""
+from __future__ import division
+
+from random import sample, choice
+from sys import argv
+from string import ascii_letters
+
+import numpy as np, pandas as pd
+from emperor import Emperor
+from emperor.util import get_emperor_support_files_dir
+from skbio import OrdinationResults
+
+
+def listify(a):
+    return np.asarray(a, dtype='str').tolist()
+
+N = 10
+if len(argv) > 1:
+    N = int(argv[1])
+
+categories = np.asarray(np.random.randint(1, 1000, N), str)
+
+coords_ids = listify(np.arange(N))
+coords = (np.random.randn(N, 10) * 0.25).tolist()
+pct_var = 1/np.exp(np.arange(10))
+
+
+md_headers = ['SampleID', 'DOB', 'Strings']
+metadata = []
+for _id in coords_ids:
+    metadata.append([_id, ''.join(sample(set(categories), 1)), ''.join(choice(
+        ascii_letters) for x in range(10))])
+
+samples = pd.DataFrame(index=coords_ids, data=coords)
+
+mf = pd.DataFrame(data=metadata, columns=md_headers)
+mf.set_index('SampleID', inplace=True)
+
+res = OrdinationResults(short_method_name='PC', long_method_name='Principal '
+                        'Coordinates Analysis', eigvals=pct_var,
+                        samples=samples, proportion_explained=pct_var)
+
+
+viz = Emperor(res, mf, remote=get_emperor_support_files_dir())
+
+with open('new-emperor.html', 'w') as f:
+    f.write(viz.make_emperor(standalone=True))
diff --git a/examples/costello/mapping-file.txt b/examples/costello/mapping-file.txt
new file mode 100644
index 0000000..3b802d8
--- /dev/null
+++ b/examples/costello/mapping-file.txt
@@ -0,0 +1,603 @@
+#SampleID	BarcodeSequence	LinkerPrimerSequence	barcode_read_group_tag	dna_extracted_prep	experiment_alias	experiment_center	experiment_design_description	experiment_title	key_seq	library_construction_protocol	linker	nucl_acid_amp	nucl_acid_ext	pcr_cond	pcr_primers	physical_specimen_remaining_prep	platform	pool_member_name	pool_proportion	primer_read_group_tag	region	run_alias	run_center	run_date	run_prefix	samp_collect_device_prep	samp_size	sample_center	sample_type_prep	sequencing_meth	 [...]
+449.M22Indr	CGAGCAGCACAT	CATGCTGCCTCCCGTAGGAGT	M22Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Fotl	GACGATATCGCG	CATGCTGCCTCCCGTAGGAGT	M14Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Nstr	GCAGGATAGATA	CATGCTGCCTCCCGTAGGAGT	F31Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Labi	AGATGTTCTGCT	CATGCTGCCTCCCGTAGGAGT	F11Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Indl	CGAGAGTTACGC	CATGCTGCCTCCCGTAGGAGT	M22Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Fotr	GACGAGTCAGTC	CATGCTGCCTCCCGTAGGAGT	M14Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Fcsw	GACTAGACCAGC	CATGCTGCCTCCCGTAGGAGT	M14Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Plmr	GCTGTAGTATGC	CATGCTGCCTCCCGTAGGAGT	M33Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Ewax	TAGCTGAGTCCA	CATGCTGCCTCCCGTAGGAGT	M54Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Indr	ACGTGCCGTAGA	CATGCTGCCTCCCGTAGGAGT	M12Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Indl	ACGTGAGAGAAT	CATGCTGCCTCCCGTAGGAGT	M12Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Ewxl	CTAGCGAACATC	CATGCTGCCTCCCGTAGGAGT	M32Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Hair	CTCAGTATGCAG	CATGCTGCCTCCCGTAGGAGT	M32Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Urin	AGCTCTCAGAGG	CATGCTGCCTCCCGTAGGAGT	F11Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Urin	TCAGTACGAGGC	CATGCTGCCTCCCGTAGGAGT	M64Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Navl	ACTACAGCCTAT	CATGCTGCCTCCCGTAGGAGT	M12Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Kner	CTAGAGACTCTT	CATGCTGCCTCCCGTAGGAGT	M32Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Aptr	CTGGACTCATAG	CATGCTGCCTCCCGTAGGAGT	M41Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Fotr	GACGAGTCAGTC	CATGCTGCCTCCCGTAGGAGT	M41Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Mout	CATAGCGAGTTC	CATGCTGCCTCCCGTAGGAGT	M21Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Fcsw	TCAGTGACGTAC	CATGCTGCCTCCCGTAGGAGT	M64Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Plml	GACAGTTACTGC	CATGCTGCCTCCCGTAGGAGT	M14Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Plml	AGCCATACTGAC	CATGCTGCCTCCCGTAGGAGT	F11Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Navl	ATGACCATCGTG	CATGCTGCCTCCCGTAGGAGT	F21Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Plmr	AGCGACTGTGCA	CATGCTGCCTCCCGTAGGAGT	F11Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Plmr	GACAGGAGATAG	CATGCTGCCTCCCGTAGGAGT	M14Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Ewax	GAGACAGCTTGC	CATGCTGCCTCCCGTAGGAGT	F13Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Knel	CTAGAACGCACT	CATGCTGCCTCCCGTAGGAGT	M32Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Aptl	CTGCTGCGAAGA	CATGCTGCCTCCCGTAGGAGT	M41Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Plml	ACATGATCGTTC	CATGCTGCCTCCCGTAGGAGT	M11Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Ewax	TATGGCACACAC	CATGCTGCCTCCCGTAGGAGT	M63Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Knel	ACGAGTGCTATC	CATGCTGCCTCCCGTAGGAGT	M12Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Plmr	GATCAGAAGATG	CATGCTGCCTCCCGTAGGAGT	M23Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Plmr	GCTGTGTAGGAC	CATGCTGCCTCCCGTAGGAGT	F32Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Plml	CATCGTATCAAC	CATGCTGCCTCCCGTAGGAGT	M21Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Nose	GAGCTGGCTGAT	CATGCTGCCTCCCGTAGGAGT	M42Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Plml	GCTGTAGTATGC	CATGCTGCCTCCCGTAGGAGT	F32Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Plmr	CATCTGTAGCGA	CATGCTGCCTCCCGTAGGAGT	M21Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Frhd	ATCGTACAACTC	CATGCTGCCTCCCGTAGGAGT	F21Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Mout	GAAGCTACTGTC	CATGCTGCCTCCCGTAGGAGT	M41Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Nose	CGAGTTGTAGCG	CATGCTGCCTCCCGTAGGAGT	M22Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Kner	ACGATGCGACCA	CATGCTGCCTCCCGTAGGAGT	M12Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Plml	GATCCGACACTA	CATGCTGCCTCCCGTAGGAGT	M23Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Plmr	ACATGTCACGTG	CATGCTGCCTCCCGTAGGAGT	M11Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Mout	CTCCTACTGTCT	CATGCTGCCTCCCGTAGGAGT	M32Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Pinl	CATGAGTGCTAC	CATGCTGCCTCCCGTAGGAGT	M21Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Fotr	GTCTCATGTAGG	CATGCTGCCTCCCGTAGGAGT	F34Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Labi	CACATCTAACAC	CATGCTGCCTCCCGTAGGAGT	F22Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Urin	GGCGTACTGATG	CATGCTGCCTCCCGTAGGAGT	M33Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Uric	GGCTATGACATC	CATGCTGCCTCCCGTAGGAGT	M33Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Fcsp	CGTAAGTCTACT	CATGCTGCCTCCCGTAGGAGT	M31Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Urin	CATTCGATGACT	CATGCTGCCTCCCGTAGGAGT	M21Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Mout	GAGCAGATGCCT	CATGCTGCCTCCCGTAGGAGT	M42Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Nstr	CATCATGAGGCT	CATGCTGCCTCCCGTAGGAGT	M21Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Fcsw	CGTACAGTTATC	CATGCTGCCTCCCGTAGGAGT	M31Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Knee	GTACGGCATACG	CATGCTGCCTCCCGTAGGAGT	M34Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Glns	ACACTAGATCCG	CATGCTGCCTCCCGTAGGAGT	M11Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Fotl	GAGTGAGTACAA	CATGCTGCCTCCCGTAGGAGT	F14Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Kner	AGAACACGTCTC	CATGCTGCCTCCCGTAGGAGT	F11Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Fcsw	TCACAGATCCGA	CATGCTGCCTCCCGTAGGAGT	M63Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Fotr	GAGTCTGAGTCT	CATGCTGCCTCCCGTAGGAGT	F14Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Navl	ACAGCTAGCTTG	CATGCTGCCTCCCGTAGGAGT	M11Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Nstl	CATCAGCGTGTA	CATGCTGCCTCCCGTAGGAGT	M21Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Fotr	GGACGTCACAGT	CATGCTGCCTCCCGTAGGAGT	M33Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Tong	GGCGACATGTAC	CATGCTGCCTCCCGTAGGAGT	M33Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Nstl	ACAGTTGCGCGA	CATGCTGCCTCCCGTAGGAGT	M11Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Fotr	GTATGTTGCTCA	CATGCTGCCTCCCGTAGGAGT	F33Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Nstr	ACATCACTTAGC	CATGCTGCCTCCCGTAGGAGT	M11Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Fotl	GTCAACGCGATG	CATGCTGCCTCCCGTAGGAGT	F33Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Fcsw	ATCGATCTGTGG	CATGCTGCCTCCCGTAGGAGT	F21Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Nost	GATCGTCCAGAT	CATGCTGCCTCCCGTAGGAGT	M23Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Fcsp	ATCCTCAGTAGT	CATGCTGCCTCCCGTAGGAGT	F21Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Tong	TATTCGTGTCAG	CATGCTGCCTCCCGTAGGAGT	M63Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Fcsw	GCTGGTATCTGA	CATGCTGCCTCCCGTAGGAGT	F24Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Pinr	ATACGTCTTCGA	CATGCTGCCTCCCGTAGGAGT	F12Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Tong	CTACATCTAAGC	CATGCTGCCTCCCGTAGGAGT	M31Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Indl	GCTAGTCTGAAC	CATGCTGCCTCCCGTAGGAGT	F32Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Pinl	CTCTGCTAGCCT	CATGCTGCCTCCCGTAGGAGT	M32Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Urin	GTCTTCGTCGCT	CATGCTGCCTCCCGTAGGAGT	F34Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Nost	GCTAGATGCCAG	CATGCTGCCTCCCGTAGGAGT	F24Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Forr	CGTAGAACGTGC	CATGCTGCCTCCCGTAGGAGT	M31Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Plml	GCGTTACACACA	CATGCTGCCTCCCGTAGGAGT	F24Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Uric	GTGACCTGATGT	CATGCTGCCTCCCGTAGGAGT	F34Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Plml	TCACTATGGTCA	CATGCTGCCTCCCGTAGGAGT	M64Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Knee	TATCTCGAACTG	CATGCTGCCTCCCGTAGGAGT	M63Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Urin	ATAGGCGATCTC	CATGCTGCCTCCCGTAGGAGT	F12Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Plmr	GCGTATCTTGAT	CATGCTGCCTCCCGTAGGAGT	F24Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Forl	CGTACTAGACTG	CATGCTGCCTCCCGTAGGAGT	M31Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Nost	GTACAAGAGTGA	CATGCTGCCTCCCGTAGGAGT	M34Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Fcsp	CTAGTCAGCTGA	CATGCTGCCTCCCGTAGGAGT	M32Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Tong	GAAGTCTCGCAT	CATGCTGCCTCCCGTAGGAGT	M13Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Fcsw	CTATAGTCGTGT	CATGCTGCCTCCCGTAGGAGT	M32Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Indr	GCTATCACGAGT	CATGCTGCCTCCCGTAGGAGT	F32Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Pinr	CTGAACGCTAGT	CATGCTGCCTCCCGTAGGAGT	M32Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Tong	CATGTCTCTCCG	CATGCTGCCTCCCGTAGGAGT	M21Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Frhd	ACACGGTGTCTA	CATGCTGCCTCCCGTAGGAGT	M11Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Tong	GACGCTAGTTCA	CATGCTGCCTCCCGTAGGAGT	M14Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Knee	GCTAGTCTGAAC	CATGCTGCCTCCCGTAGGAGT	F24Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Frhd	CGACAGCTGACA	CATGCTGCCTCCCGTAGGAGT	M22Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Indl	GAGAGCTCTACG	CATGCTGCCTCCCGTAGGAGT	M42Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Forl	CTATCAGTGTAC	CATGCTGCCTCCCGTAGGAGT	M32Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Pinr	CGTTCGCATAGA	CATGCTGCCTCCCGTAGGAGT	M31Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Uric	TCAGTCGACGAG	CATGCTGCCTCCCGTAGGAGT	M64Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Aptr	AGCTTGACAGCT	CATGCTGCCTCCCGTAGGAGT	F12Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Pinr	TGCGCGAATACT	CATGCTGCCTCCCGTAGGAGT	F11Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Nose	CACGGACTATAC	CATGCTGCCTCCCGTAGGAGT	F22Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Plml	GCTGTGTAGGAC	CATGCTGCCTCCCGTAGGAGT	M33Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Pinl	AGCGAGCTATCT	CATGCTGCCTCCCGTAGGAGT	F11Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Aptl	AGCTGACTAGTC	CATGCTGCCTCCCGTAGGAGT	F12Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Fotr	CTACACAAGCAC	CATGCTGCCTCCCGTAGGAGT	M31Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Pinl	CGTTATGTACAC	CATGCTGCCTCCCGTAGGAGT	M31Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Fotl	CTAACGCAGTCA	CATGCTGCCTCCCGTAGGAGT	M31Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Nost	GACCACTACGAT	CATGCTGCCTCCCGTAGGAGT	M14Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Forr	GATGTCGTGTCA	CATGCTGCCTCCCGTAGGAGT	F31Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Forl	GATGCATGACGC	CATGCTGCCTCCCGTAGGAGT	F31Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Knee	GATCTATCCGAG	CATGCTGCCTCCCGTAGGAGT	M23Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Indl	ACAGACCACTCA	CATGCTGCCTCCCGTAGGAGT	M11Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Frhd	GTGCAATCGACG	CATGCTGCCTCCCGTAGGAGT	M43Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Urin	ACTGTACGCGTA	CATGCTGCCTCCCGTAGGAGT	M12Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Mout	CGTCGATCTCTC	CATGCTGCCTCCCGTAGGAGT	M31Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Ewxl	ATCAGGCGTGTG	CATGCTGCCTCCCGTAGGAGT	F21Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Knee	TCAGACAGACCG	CATGCTGCCTCCCGTAGGAGT	M64Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Ewax	GGCAGTGTATCG	CATGCTGCCTCCCGTAGGAGT	M33Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Knee	GCCACTGATAGT	CATGCTGCCTCCCGTAGGAGT	F23Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Glns	GAGACAGCTTGC	CATGCTGCCTCCCGTAGGAGT	M42Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Forr	GCGTTACACACA	CATGCTGCCTCCCGTAGGAGT	F32Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Plml	CTCTCTACCTGT	CATGCTGCCTCCCGTAGGAGT	M32Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Plml	CGTGTGATCAGG	CATGCTGCCTCCCGTAGGAGT	M31Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Forr	CAAGATCGACTC	CATGCTGCCTCCCGTAGGAGT	F22Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Plmr	CGTTACTAGAGC	CATGCTGCCTCCCGTAGGAGT	M31Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Forl	CAACTCATCGTA	CATGCTGCCTCCCGTAGGAGT	F22Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Fcsw	ACGCTATCTGGA	CATGCTGCCTCCCGTAGGAGT	M12Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Fcsp	ACGCGCAGATAC	CATGCTGCCTCCCGTAGGAGT	M12Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Fotl	TATGCGAGGTCG	CATGCTGCCTCCCGTAGGAGT	M63Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Indr	ACAGAGTCGGCT	CATGCTGCCTCCCGTAGGAGT	M11Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Forl	GCGTATCTTGAT	CATGCTGCCTCCCGTAGGAGT	F32Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Nost	GCACTCGTTAGA	CATGCTGCCTCCCGTAGGAGT	M24Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Nose	ACAGTGCTTCAT	CATGCTGCCTCCCGTAGGAGT	M11Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Uric	GATGTGAGCGCT	CATGCTGCCTCCCGTAGGAGT	M23Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Fotl	GAAGAGTGATCA	CATGCTGCCTCCCGTAGGAGT	M13Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Uric	GAGATGCCGACT	CATGCTGCCTCCCGTAGGAGT	F13Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Frhd	AGTCTACTCTGA	CATGCTGCCTCCCGTAGGAGT	F12Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Mout	ACAGCAGTGGTC	CATGCTGCCTCCCGTAGGAGT	M11Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Fotr	GAACTGTATCTC	CATGCTGCCTCCCGTAGGAGT	M13Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Knee	GAACATGATGAG	CATGCTGCCTCCCGTAGGAGT	M13Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Knee	GTATGCGCTGTA	CATGCTGCCTCCCGTAGGAGT	F33Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Nost	GAGTAGCTCGTG	CATGCTGCCTCCCGTAGGAGT	F14Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Fotr	GCAGCACGTTGA	CATGCTGCCTCCCGTAGGAGT	M24Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Fotr	GACTTCAGTGTG	CATGCTGCCTCCCGTAGGAGT	F13Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Urin	CTGCAGTACTTA	CATGCTGCCTCCCGTAGGAGT	M32Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Fotr	ATACTCACTCAG	CATGCTGCCTCCCGTAGGAGT	F12Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Plmr	GCAGTATCACTG	CATGCTGCCTCCCGTAGGAGT	F31Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Plml	GCAGGCAGTACT	CATGCTGCCTCCCGTAGGAGT	F31Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Fotl	ATACTATTGCGC	CATGCTGCCTCCCGTAGGAGT	F12Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Nost	TAACTCTGATGC	CATGCTGCCTCCCGTAGGAGT	M44Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Fotl	GCAGCCGAGTAT	CATGCTGCCTCCCGTAGGAGT	M24Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Fotl	GAGAATACGTGA	CATGCTGCCTCCCGTAGGAGT	F13Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Hair	ACGTCTGTAGCA	CATGCTGCCTCCCGTAGGAGT	M12Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Ewxl	AGACCGTCAGAC	CATGCTGCCTCCCGTAGGAGT	F11Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Ewax	GAGTGGTAGAGA	CATGCTGCCTCCCGTAGGAGT	F14Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Knee	TACTACATGGTC	CATGCTGCCTCCCGTAGGAGT	M53Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Aptl	ATATCGCTACTG	CATGCTGCCTCCCGTAGGAGT	F21Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Ewax	GCGACTTGTGTA	CATGCTGCCTCCCGTAGGAGT	F23Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Fcsw	GTCGACTCCTCT	CATGCTGCCTCCCGTAGGAGT	F33Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Fotl	ACTCTTCTAGAG	CATGCTGCCTCCCGTAGGAGT	M12Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Navl	GCTCGCTACTTC	CATGCTGCCTCCCGTAGGAGT	F32Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Fcsw	GATATGCGGCTG	CATGCTGCCTCCCGTAGGAGT	F14Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Urin	ATGGTCTACTAC	CATGCTGCCTCCCGTAGGAGT	F21Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Pinl	CGATGTCGTCAA	CATGCTGCCTCCCGTAGGAGT	M22Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Plmr	GACTCACTCAAT	CATGCTGCCTCCCGTAGGAGT	F13Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Kner	AGGCTACACGAC	CATGCTGCCTCCCGTAGGAGT	F12Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Fotl	GATACGTCCTGA	CATGCTGCCTCCCGTAGGAGT	M42Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Fotl	GACCGAGCTATG	CATGCTGCCTCCCGTAGGAGT	M41Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Fotr	ACTGACAGCCAT	CATGCTGCCTCCCGTAGGAGT	M12Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Fotr	GATAGCTGTCTT	CATGCTGCCTCCCGTAGGAGT	M42Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Frhd	GCTAAGAGAGTA	CATGCTGCCTCCCGTAGGAGT	F32Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Knel	AGGACGCACTGT	CATGCTGCCTCCCGTAGGAGT	F12Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Plml	GACTCGAATCGT	CATGCTGCCTCCCGTAGGAGT	F13Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Tong	CTGAGCAGAGTC	CATGCTGCCTCCCGTAGGAGT	M32Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Mout	ATCTTAGACTGC	CATGCTGCCTCCCGTAGGAGT	F21Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Indr	CACAGTGGACGT	CATGCTGCCTCCCGTAGGAGT	F22Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Nstr	GCTGGTATCTGA	CATGCTGCCTCCCGTAGGAGT	F32Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Knee	GTGGCGATACAC	CATGCTGCCTCCCGTAGGAGT	M43Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Frhd	GACATCGGCTAT	CATGCTGCCTCCCGTAGGAGT	M14Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Tong	CGCAGCGGTATA	CATGCTGCCTCCCGTAGGAGT	M22Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Fcsw	GAGCAGATGCCT	CATGCTGCCTCCCGTAGGAGT	F13Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Plml	GTATATCCGCAG	CATGCTGCCTCCCGTAGGAGT	F33Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Labi	GCACGACAACAC	CATGCTGCCTCCCGTAGGAGT	F31Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Plmr	GTAGTGTCTAGC	CATGCTGCCTCCCGTAGGAGT	F33Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Urin	TACATCACCACA	CATGCTGCCTCCCGTAGGAGT	M44Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Nstl	GCTGCTGCAATA	CATGCTGCCTCCCGTAGGAGT	F32Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Indl	CACAGCTCGAAT	CATGCTGCCTCCCGTAGGAGT	F22Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Nost	GTATGACTGGCT	CATGCTGCCTCCCGTAGGAGT	F33Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Navl	GAGCATTCTCTA	CATGCTGCCTCCCGTAGGAGT	M42Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Aptr	ACTGTGACTTCA	CATGCTGCCTCCCGTAGGAGT	F11Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Frhd	GACTGATCATCT	CATGCTGCCTCCCGTAGGAGT	F13Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Aptl	ACTGTCGAAGCT	CATGCTGCCTCCCGTAGGAGT	F11Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Glns	CAGTGCATATGC	CATGCTGCCTCCCGTAGGAGT	M21Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Nstr	CACGTGACATGT	CATGCTGCCTCCCGTAGGAGT	F22Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Ewxl	ACGCAACTGCTA	CATGCTGCCTCCCGTAGGAGT	M12Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Pinl	ACTCGATTCGAT	CATGCTGCCTCCCGTAGGAGT	M12Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Aptl	AACGCACGCTAG	CATGCTGCCTCCCGTAGGAGT	M11Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Frhd	GATGTGAGCGCT	CATGCTGCCTCCCGTAGGAGT	F31Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Pinr	ACTCGCACAGGA	CATGCTGCCTCCCGTAGGAGT	M12Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Ewxr	ACGCGATACTGG	CATGCTGCCTCCCGTAGGAGT	M12Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Tong	ACTGATCCTAGT	CATGCTGCCTCCCGTAGGAGT	M12Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Nstl	CACGTCGATGGA	CATGCTGCCTCCCGTAGGAGT	F22Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Indl	GCAATAGCTGCT	CATGCTGCCTCCCGTAGGAGT	F31Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Pinr	GACCACTACGAT	CATGCTGCCTCCCGTAGGAGT	M41Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Frhd	CTATGCTTGATG	CATGCTGCCTCCCGTAGGAGT	M32Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Uric	GTTAGAGCACTC	CATGCTGCCTCCCGTAGGAGT	M43Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Urin	GTGTTGCAGCAT	CATGCTGCCTCCCGTAGGAGT	M43Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Indl	CATACCAGTAGC	CATGCTGCCTCCCGTAGGAGT	M21Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Navl	GAAGTCTCGCAT	CATGCTGCCTCCCGTAGGAGT	M41Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Urin	GATGTCGTGTCA	CATGCTGCCTCCCGTAGGAGT	M23Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Ewxr	AGACGTGCACTG	CATGCTGCCTCCCGTAGGAGT	F11Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Pinl	GACATCGGCTAT	CATGCTGCCTCCCGTAGGAGT	M41Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Frhd	CTTGATGCGTAT	CATGCTGCCTCCCGTAGGAGT	M13Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Ewxr	CGGCGATGTACA	CATGCTGCCTCCCGTAGGAGT	M31Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Indr	AGTGCGATGCGT	CATGCTGCCTCCCGTAGGAGT	F12Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Ewax	GAAGCTACTGTC	CATGCTGCCTCCCGTAGGAGT	M13Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Forl	CTGTTCGTAGAG	CATGCTGCCTCCCGTAGGAGT	M41Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Forr	CTTAGCACATCA	CATGCTGCCTCCCGTAGGAGT	M41Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Indl	AGTGAGAGAAGC	CATGCTGCCTCCCGTAGGAGT	F12Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Frhd	AGAGTCCTGAGC	CATGCTGCCTCCCGTAGGAGT	F11Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Ewxl	CGGAGTGTCTAT	CATGCTGCCTCCCGTAGGAGT	M31Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Pinr	CATGCAGACTGT	CATGCTGCCTCCCGTAGGAGT	M21Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Fcsw	GGTATACGCAGC	CATGCTGCCTCCCGTAGGAGT	M33Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Tong	GATGCATGACGC	CATGCTGCCTCCCGTAGGAGT	M23Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Kner	CTGGCTGTATGA	CATGCTGCCTCCCGTAGGAGT	M41Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Knel	GATCGCAGGTGT	CATGCTGCCTCCCGTAGGAGT	F31Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Hair	GAACATGATGAG	CATGCTGCCTCCCGTAGGAGT	M41Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Knel	CTGGAGCATGAC	CATGCTGCCTCCCGTAGGAGT	M41Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Uric	GCTGCTGCAATA	CATGCTGCCTCCCGTAGGAGT	F24Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Hair	CAGTGTCAGGAC	CATGCTGCCTCCCGTAGGAGT	M21Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Urin	GCTGATGAGCTG	CATGCTGCCTCCCGTAGGAGT	F24Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Tong	CAGACTCGCAGA	CATGCTGCCTCCCGTAGGAGT	F22Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Indr	GCACATCGAGCA	CATGCTGCCTCCCGTAGGAGT	F31Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Navl	AGTGTCACGGTG	CATGCTGCCTCCCGTAGGAGT	F12Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Ewax	GCTCAGTGCAGA	CATGCTGCCTCCCGTAGGAGT	F24Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Fcsw	AGTAGTATCCTC	CATGCTGCCTCCCGTAGGAGT	F12Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Urin	GTCATTCACGAG	CATGCTGCCTCCCGTAGGAGT	F33Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Fcsp	AGTACTGCAGGC	CATGCTGCCTCCCGTAGGAGT	F12Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Uric	GTCCATAGCTAG	CATGCTGCCTCCCGTAGGAGT	F33Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Ewax	GTCACGACTATT	CATGCTGCCTCCCGTAGGAGT	F33Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Tong	ATAGCTCCATAC	CATGCTGCCTCCCGTAGGAGT	F12Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Forr	ACACGAGCCACA	CATGCTGCCTCCCGTAGGAGT	M11Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Plmr	CACTCAACAGAC	CATGCTGCCTCCCGTAGGAGT	F22Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Plml	CACTACTGTTGA	CATGCTGCCTCCCGTAGGAGT	F22Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Hair	AGATACACGCGC	CATGCTGCCTCCCGTAGGAGT	F11Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Fotl	GTAGACTGCGTG	CATGCTGCCTCCCGTAGGAGT	M34Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Indr	CGTCAGACGGAT	CATGCTGCCTCCCGTAGGAGT	M31Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Pinr	CACTGGTATATC	CATGCTGCCTCCCGTAGGAGT	F22Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Fcsp	CTGTGACATTGT	CATGCTGCCTCCCGTAGGAGT	M41Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Ewxr	CTGTCTCTCCTA	CATGCTGCCTCCCGTAGGAGT	M41Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Tong	GCGAGATCCAGT	CATGCTGCCTCCCGTAGGAGT	F23Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Fotr	CGCAGACAGACT	CATGCTGCCTCCCGTAGGAGT	M22Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Fotl	CGCACTCTAGAA	CATGCTGCCTCCCGTAGGAGT	M22Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Pinr	ATGCGTAGTGCG	CATGCTGCCTCCCGTAGGAGT	F21Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Ewxl	CTGTATCGTATG	CATGCTGCCTCCCGTAGGAGT	M41Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Urin	GAATGATGAGTG	CATGCTGCCTCCCGTAGGAGT	M13Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Ewxl	AAGCTGCAGTCG	CATGCTGCCTCCCGTAGGAGT	M11Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Aptl	GACGCTAGTTCA	CATGCTGCCTCCCGTAGGAGT	M42Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Pinl	CACTCTGATTAG	CATGCTGCCTCCCGTAGGAGT	F22Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Fotr	GTACTCTAGACT	CATGCTGCCTCCCGTAGGAGT	M34Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Plml	TACGGTATGTCT	CATGCTGCCTCCCGTAGGAGT	M53Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Fotl	TACACGATCTAC	CATGCTGCCTCCCGTAGGAGT	M44Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Frhd	TACGTGTACGTG	CATGCTGCCTCCCGTAGGAGT	M53Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Frhd	GAGAATACGTGA	CATGCTGCCTCCCGTAGGAGT	M42Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Fotr	TACACACATGGC	CATGCTGCCTCCCGTAGGAGT	M44Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Frhd	GCTTACATCGAG	CATGCTGCCTCCCGTAGGAGT	M33Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Plmr	TACGCGCTGAGA	CATGCTGCCTCCCGTAGGAGT	M53Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Knee	GACCGAGCTATG	CATGCTGCCTCCCGTAGGAGT	M14Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Hair	ATCTACTACACG	CATGCTGCCTCCCGTAGGAGT	F21Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Plml	GCATCGTCAACA	CATGCTGCCTCCCGTAGGAGT	F23Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Nstl	GCAGCCGAGTAT	CATGCTGCCTCCCGTAGGAGT	F31Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Aptr	GACGTTGCACAG	CATGCTGCCTCCCGTAGGAGT	M42Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Frhd	GTATCCATGCGA	CATGCTGCCTCCCGTAGGAGT	F33Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Fcsw	CTGTGGATCGAT	CATGCTGCCTCCCGTAGGAGT	M41Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Ewax	GCAGGATAGATA	CATGCTGCCTCCCGTAGGAGT	M24Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Urin	CTACGCGTCTCT	CATGCTGCCTCCCGTAGGAGT	M31Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Tong	ACCGCAGAGTCA	CATGCTGCCTCCCGTAGGAGT	M11Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Plmr	CTGTTCGTAGAG	CATGCTGCCTCCCGTAGGAGT	M13Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Nost	GCATTGCGTGAG	CATGCTGCCTCCCGTAGGAGT	F23Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Plmr	ATGCAGCTCAGT	CATGCTGCCTCCCGTAGGAGT	F21Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Plmr	GCATATAGTCTC	CATGCTGCCTCCCGTAGGAGT	F23Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Fotl	CTGACACGACAG	CATGCTGCCTCCCGTAGGAGT	M32Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Ewax	GACGCAGTAGCT	CATGCTGCCTCCCGTAGGAGT	M14Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Tong	GCTCGCTACTTC	CATGCTGCCTCCCGTAGGAGT	F24Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Plml	CTTAGCACATCA	CATGCTGCCTCCCGTAGGAGT	M13Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Tong	GCATGTGCATGT	CATGCTGCCTCCCGTAGGAGT	F31Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Glns	CTCAATGACTCA	CATGCTGCCTCCCGTAGGAGT	M32Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Nstl	AGTTCAGACGCT	CATGCTGCCTCCCGTAGGAGT	F12Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Mout	AGTGGATGCTCT	CATGCTGCCTCCCGTAGGAGT	F12Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Fotl	GGATCGCAGATC	CATGCTGCCTCCCGTAGGAGT	M33Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Frhd	CAAGTGAGAGAG	CATGCTGCCTCCCGTAGGAGT	F22Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Pinr	CGCACATGTTAT	CATGCTGCCTCCCGTAGGAGT	M22Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Knee	TAGCGACATCTG	CATGCTGCCTCCCGTAGGAGT	M54Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Nstr	AGTTCTACGTCA	CATGCTGCCTCCCGTAGGAGT	F12Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Fcsp	CAGGTGCTACTA	CATGCTGCCTCCCGTAGGAGT	M21Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Fcsw	CAGTACGATCTT	CATGCTGCCTCCCGTAGGAGT	M21Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Tong	TAGGTATCTCAC	CATGCTGCCTCCCGTAGGAGT	M54Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Tong	ATGGCGTGCACA	CATGCTGCCTCCCGTAGGAGT	F21Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Fotl	AGCGTAGGTCGT	CATGCTGCCTCCCGTAGGAGT	F11Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Knel	CGCTAGAACGCA	CATGCTGCCTCCCGTAGGAGT	M31Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Ewxl	GACTCACTCAAT	CATGCTGCCTCCCGTAGGAGT	M42Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Navl	CGTGACAATGTC	CATGCTGCCTCCCGTAGGAGT	M31Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Tong	GAGAGAATGATC	CATGCTGCCTCCCGTAGGAGT	F13Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Uric	GCAGTTCATATC	CATGCTGCCTCCCGTAGGAGT	M24Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Ewxr	GACTCGAATCGT	CATGCTGCCTCCCGTAGGAGT	M42Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Kner	CGCTTATCGAGA	CATGCTGCCTCCCGTAGGAGT	M31Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Uric	GACACTCGAATC	CATGCTGCCTCCCGTAGGAGT	M13Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Nost	GACTGCATCTTA	CATGCTGCCTCCCGTAGGAGT	F13Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Fotr	AGCTATCCACGA	CATGCTGCCTCCCGTAGGAGT	F11Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Forl	CAGTCACTAACG	CATGCTGCCTCCCGTAGGAGT	M21Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Urin	GCAGTATCACTG	CATGCTGCCTCCCGTAGGAGT	M24Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Hair	GCTAGATGCCAG	CATGCTGCCTCCCGTAGGAGT	F32Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Mout	GCTCAGTGCAGA	CATGCTGCCTCCCGTAGGAGT	F32Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Pinr	GCATAGTAGCCG	CATGCTGCCTCCCGTAGGAGT	F31Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Indl	CTCATGTACAGT	CATGCTGCCTCCCGTAGGAGT	M32Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Pinl	GCTTACATCGAG	CATGCTGCCTCCCGTAGGAGT	F32Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Frhd	TCACTGGCAGTA	CATGCTGCCTCCCGTAGGAGT	M64Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Pinr	GCTTCATAGTGT	CATGCTGCCTCCCGTAGGAGT	F32Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Indr	CTCCACATGAGA	CATGCTGCCTCCCGTAGGAGT	M32Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Pinl	GCAGTTCATATC	CATGCTGCCTCCCGTAGGAGT	F31Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Hair	GATTAGCACTCT	CATGCTGCCTCCCGTAGGAGT	F31Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Indl	CGTCACGACTAA	CATGCTGCCTCCCGTAGGAGT	M31Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Fotl	GCTTGCGAGACA	CATGCTGCCTCCCGTAGGAGT	F32Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Nost	TACTAATCTGCG	CATGCTGCCTCCCGTAGGAGT	M53Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Nstr	AGCATATGAGAG	CATGCTGCCTCCCGTAGGAGT	F11Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Nstl	AGCAGTCGCGAT	CATGCTGCCTCCCGTAGGAGT	F11Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Fotr	GGACGTCACAGT	CATGCTGCCTCCCGTAGGAGT	F32Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Knee	GAGTATGCAGCC	CATGCTGCCTCCCGTAGGAGT	F14Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Frhd	GGTGCGTGTATG	CATGCTGCCTCCCGTAGGAGT	M34Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Forr	ACGGATCGTCAG	CATGCTGCCTCCCGTAGGAGT	M12Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Fotr	TACTGCGACAGT	CATGCTGCCTCCCGTAGGAGT	M53Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Aptr	CCAGATGATCGT	CATGCTGCCTCCCGTAGGAGT	M22Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Aptr	ATATGCCAGTGC	CATGCTGCCTCCCGTAGGAGT	F21Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Uric	GATAGTGCCACT	CATGCTGCCTCCCGTAGGAGT	F14Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Urin	GAGAGCTCTACG	CATGCTGCCTCCCGTAGGAGT	F13Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Nose	AGCAGCACTTGT	CATGCTGCCTCCCGTAGGAGT	F11Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Nose	AGTGTTCGATCG	CATGCTGCCTCCCGTAGGAGT	F12Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Nost	GCTTCATAGTGT	CATGCTGCCTCCCGTAGGAGT	M33Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Aptl	CATTGTCTGTGA	CATGCTGCCTCCCGTAGGAGT	M22Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Fotl	TACTGGACGCGA	CATGCTGCCTCCCGTAGGAGT	M53Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Urin	GATAGCTGTCTT	CATGCTGCCTCCCGTAGGAGT	F14Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Forl	ACGCTCATGGAT	CATGCTGCCTCCCGTAGGAGT	M12Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Forl	AGTCACATCACT	CATGCTGCCTCCCGTAGGAGT	F12Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Fcsw	TACGATGACCAC	CATGCTGCCTCCCGTAGGAGT	M44Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Frhd	CGTATCTGCGAA	CATGCTGCCTCCCGTAGGAGT	M31Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Forr	AGTCCATAGCTG	CATGCTGCCTCCCGTAGGAGT	F12Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Fcsw	GCGTACAACTGT	CATGCTGCCTCCCGTAGGAGT	F23Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Nstr	TCATCGCGATAT	CATGCTGCCTCCCGTAGGAGT	F21Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F13Knee	GACTGTCATGCA	CATGCTGCCTCCCGTAGGAGT	F13Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Nost	TAGCCTCTCTGC	CATGCTGCCTCCCGTAGGAGT	M54Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Fotr	GATCTCATAGGC	CATGCTGCCTCCCGTAGGAGT	M23Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Hair	AGTCTCGCATAT	CATGCTGCCTCCCGTAGGAGT	F12Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Fotl	GATCTTCAGTAC	CATGCTGCCTCCCGTAGGAGT	M23Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Nstl	ATGAGACTCCAC	CATGCTGCCTCCCGTAGGAGT	F21Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Fcsw	TAGTGTGCTTCA	CATGCTGCCTCCCGTAGGAGT	M54Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Tong	GGATCGCAGATC	CATGCTGCCTCCCGTAGGAGT	F32Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Fotr	ACCAGCGACTAG	CATGCTGCCTCCCGTAGGAGT	M11Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Navl	CATATACTCGCA	CATGCTGCCTCCCGTAGGAGT	M21Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Knel	CCAGTGTATGCA	CATGCTGCCTCCCGTAGGAGT	M22Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Knee	TAAGCGCAGCAC	CATGCTGCCTCCCGTAGGAGT	M44Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Kner	CCATACATAGCT	CATGCTGCCTCCCGTAGGAGT	M22Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Fotl	ACCAGACGATGC	CATGCTGCCTCCCGTAGGAGT	M11Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Urin	GATATGCGGCTG	CATGCTGCCTCCCGTAGGAGT	M42Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Nost	TATCGCGCGATA	CATGCTGCCTCCCGTAGGAGT	M63Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Forr	GACTTCAGTGTG	CATGCTGCCTCCCGTAGGAGT	M42Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Fcsw	GACTGCATCTTA	CATGCTGCCTCCCGTAGGAGT	M42Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Ewxr	ATCCGATCACAG	CATGCTGCCTCCCGTAGGAGT	F21Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Fcsp	GACTGATCATCT	CATGCTGCCTCCCGTAGGAGT	M42Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Plml	ACTCACGGTATG	CATGCTGCCTCCCGTAGGAGT	M12Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Tong	GATAGTGCCACT	CATGCTGCCTCCCGTAGGAGT	M42Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Forl	GACTGTCATGCA	CATGCTGCCTCCCGTAGGAGT	M42Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Hair	CGTCAACGATGT	CATGCTGCCTCCCGTAGGAGT	M31Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Uric	GCGGATGTGACT	CATGCTGCCTCCCGTAGGAGT	F23Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Forr	ATCGCTCGAGGA	CATGCTGCCTCCCGTAGGAGT	F21Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Hair	CGACTTATGTGT	CATGCTGCCTCCCGTAGGAGT	M22Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Hair	GAGAGAATGATC	CATGCTGCCTCCCGTAGGAGT	M42Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Plmr	GAGCATTCTCTA	CATGCTGCCTCCCGTAGGAGT	F14Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Urin	GCGATATATCGC	CATGCTGCCTCCCGTAGGAGT	F23Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Plml	GAGCTGGCTGAT	CATGCTGCCTCCCGTAGGAGT	F14Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Forl	ATCGCGGACGAT	CATGCTGCCTCCCGTAGGAGT	F21Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Ewxl	GCGAGATCCAGT	CATGCTGCCTCCCGTAGGAGT	F32Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Aptr	GCCAGAGTCGTA	CATGCTGCCTCCCGTAGGAGT	F32Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Frhd	ACGGTGAGTGTC	CATGCTGCCTCCCGTAGGAGT	M12Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Aptl	GCCACTGATAGT	CATGCTGCCTCCCGTAGGAGT	F32Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Ewxr	GCGATATATCGC	CATGCTGCCTCCCGTAGGAGT	F32Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Urin	GTAGCAACGTCT	CATGCTGCCTCCCGTAGGAGT	M34Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Knee	GCACTGAGACGT	CATGCTGCCTCCCGTAGGAGT	M24Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Uric	GTAGCGCGAGTT	CATGCTGCCTCCCGTAGGAGT	M34Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Plml	TAGCACACCTAT	CATGCTGCCTCCCGTAGGAGT	M54Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Glns	CTTGTGTCGATA	CATGCTGCCTCCCGTAGGAGT	M41Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Knel	AACTGTGCGTAC	CATGCTGCCTCCCGTAGGAGT	M11Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Plmr	ACTCAGATACTC	CATGCTGCCTCCCGTAGGAGT	M12Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Pinl	ACATTCAGCGCA	CATGCTGCCTCCCGTAGGAGT	M11Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Nstr	CGTGTACATCAG	CATGCTGCCTCCCGTAGGAGT	M31Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Frhd	GTCGTGTGTCAA	CATGCTGCCTCCCGTAGGAGT	F34Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Nose	GCTGATGAGCTG	CATGCTGCCTCCCGTAGGAGT	F32Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Nstl	CGTGCATTATCA	CATGCTGCCTCCCGTAGGAGT	M31Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Frhd	GCATGTGCATGT	CATGCTGCCTCCCGTAGGAGT	F23Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Pinr	ACCACATACATC	CATGCTGCCTCCCGTAGGAGT	M11Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Fcsw	GACAGCGTTGAC	CATGCTGCCTCCCGTAGGAGT	M13Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Mout	AGCACACCTACA	CATGCTGCCTCCCGTAGGAGT	F11Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Urin	TAGTCGTCTAGT	CATGCTGCCTCCCGTAGGAGT	M54Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Frhd	CAGTGATCCTAG	CATGCTGCCTCCCGTAGGAGT	M21Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Knel	ACTTGTAGCAGC	CATGCTGCCTCCCGTAGGAGT	F11Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Uric	TAGTGCTGCGTA	CATGCTGCCTCCCGTAGGAGT	M54Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Fotl	GTCTCTCTACGC	CATGCTGCCTCCCGTAGGAGT	F34Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Fcsw	GATGATCGCCGA	CATGCTGCCTCCCGTAGGAGT	F31Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Fcsp	GATCTTCAGTAC	CATGCTGCCTCCCGTAGGAGT	F31Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Labi	AGTTAGTGCGTC	CATGCTGCCTCCCGTAGGAGT	F12Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Ewax	GTAGAGCTGTTC	CATGCTGCCTCCCGTAGGAGT	M34Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Plmr	GTTGACGACAGC	CATGCTGCCTCCCGTAGGAGT	M44Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Plml	GTGATAGTGCCG	CATGCTGCCTCCCGTAGGAGT	M43Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Forr	AGAGTAGCTAAG	CATGCTGCCTCCCGTAGGAGT	F11Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M33Knee	GCTTGCGAGACA	CATGCTGCCTCCCGTAGGAGT	M33Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Plmr	GAGTCTGAGTCT	CATGCTGCCTCCCGTAGGAGT	M42Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Plml	GAGTATGCAGCC	CATGCTGCCTCCCGTAGGAGT	M42Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Fcsw	GCGTACAACTGT	CATGCTGCCTCCCGTAGGAGT	F32Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Fcsp	GCGGATGTGACT	CATGCTGCCTCCCGTAGGAGT	F32Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Forl	AGAGCAAGAGCA	CATGCTGCCTCCCGTAGGAGT	F11Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Frhd	TATCAGGTGTGC	CATGCTGCCTCCCGTAGGAGT	M63Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Plml	GTTGTATACTCG	CATGCTGCCTCCCGTAGGAGT	M44Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Plmr	GTGAGGTCGCTA	CATGCTGCCTCCCGTAGGAGT	M43Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Ewxr	GATCTCATAGGC	CATGCTGCCTCCCGTAGGAGT	F31Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F33Tong	GTCATATCGTAC	CATGCTGCCTCCCGTAGGAGT	F33Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Fcsw	TAGATAGCAGGA	CATGCTGCCTCCCGTAGGAGT	M53Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Fotl	GCTATTCGACAT	CATGCTGCCTCCCGTAGGAGT	F24Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Fotl	TCAGCCATGACA	CATGCTGCCTCCCGTAGGAGT	M64Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Mout	GCACTCGTTAGA	CATGCTGCCTCCCGTAGGAGT	F31Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Knee	GTCTATCGGAGT	CATGCTGCCTCCCGTAGGAGT	F34Knee	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Fotr	TCAGATCCGATG	CATGCTGCCTCCCGTAGGAGT	M64Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Navl	CACGACAGGCTA	CATGCTGCCTCCCGTAGGAGT	F22Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Fcsw	CAACTATCAGCT	CATGCTGCCTCCCGTAGGAGT	F22Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Fotr	GCTATCACGAGT	CATGCTGCCTCCCGTAGGAGT	F24Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Fcsp	CAACACGCACGA	CATGCTGCCTCCCGTAGGAGT	F22Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Glns	ACGTACTCAGTG	CATGCTGCCTCCCGTAGGAGT	M12Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Indr	AGATCTCTGCAT	CATGCTGCCTCCCGTAGGAGT	F11Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Tong	GTGTGTGTCAGG	CATGCTGCCTCCCGTAGGAGT	M43Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Kner	GATCGTCCAGAT	CATGCTGCCTCCCGTAGGAGT	F31Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Plmr	CTCTGAAGTCTA	CATGCTGCCTCCCGTAGGAGT	M32Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Nost	GTGCACATTATC	CATGCTGCCTCCCGTAGGAGT	M43Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Indr	CATAGACGTTCG	CATGCTGCCTCCCGTAGGAGT	M21Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Tong	TACAGTCTCATG	CATGCTGCCTCCCGTAGGAGT	M44Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Labi	ATCTGGTGCTAT	CATGCTGCCTCCCGTAGGAGT	F21Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Kner	ATCACTAGTCAC	CATGCTGCCTCCCGTAGGAGT	F21Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Fotr	GCATCGTCAACA	CATGCTGCCTCCCGTAGGAGT	F31Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Fotl	GCATATAGTCTC	CATGCTGCCTCCCGTAGGAGT	F31Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Knel	ATCACGTAGCGG	CATGCTGCCTCCCGTAGGAGT	F21Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Indl	GAACTGTATCTC	CATGCTGCCTCCCGTAGGAGT	M41Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Knel	GACTAACGTCAC	CATGCTGCCTCCCGTAGGAGT	M42Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Frhd	GATCGCAGGTGT	CATGCTGCCTCCCGTAGGAGT	M23Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Plmr	TAGTTGCGAGTC	CATGCTGCCTCCCGTAGGAGT	M63Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Nstr	CGATATTCATCG	CATGCTGCCTCCCGTAGGAGT	M22Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Glns	CGTATGCTGTAT	CATGCTGCCTCCCGTAGGAGT	M31Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Fotl	GCCTATACTACA	CATGCTGCCTCCCGTAGGAGT	F23Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F23Fotr	GCCAGAGTCGTA	CATGCTGCCTCCCGTAGGAGT	F23Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Uric	TACCGCTAGTAG	CATGCTGCCTCCCGTAGGAGT	M44Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Nstl	CGATAGATCTTC	CATGCTGCCTCCCGTAGGAGT	M22Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Plml	TATACGCGCATT	CATGCTGCCTCCCGTAGGAGT	M63Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Kner	GACTAGACCAGC	CATGCTGCCTCCCGTAGGAGT	M42Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Indr	GAAGAGTGATCA	CATGCTGCCTCCCGTAGGAGT	M41Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Fotr	CAGACATTGCGT	CATGCTGCCTCCCGTAGGAGT	F22Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Frhd	TAGCATCGTGGT	CATGCTGCCTCCCGTAGGAGT	M54Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Fotr	CTGAGATACGCG	CATGCTGCCTCCCGTAGGAGT	M32Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Fcsw	AGAGAGCAAGTG	CATGCTGCCTCCCGTAGGAGT	F11Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Fcsp	AGACTGCGTACT	CATGCTGCCTCCCGTAGGAGT	F11Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Plml	ATGCACTGGCGA	CATGCTGCCTCCCGTAGGAGT	F21Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Fotl	CACTGTAGGACG	CATGCTGCCTCCCGTAGGAGT	F22Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Plml	GTCGTAGCCAGA	CATGCTGCCTCCCGTAGGAGT	F34Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Aptl	GATCAGAAGATG	CATGCTGCCTCCCGTAGGAGT	F31Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Fcsp	CCTAGTACTGAT	CATGCTGCCTCCCGTAGGAGT	M22Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Plml	ATAATCTCGTCG	CATGCTGCCTCCCGTAGGAGT	F12Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Ewax	TACAGATGGCTC	CATGCTGCCTCCCGTAGGAGT	M44Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Plmr	TCACGATTAGCG	CATGCTGCCTCCCGTAGGAGT	M64Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Plmr	ATACACGTGGCG	CATGCTGCCTCCCGTAGGAGT	F12Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Aptr	GATCCGACACTA	CATGCTGCCTCCCGTAGGAGT	F31Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Urin	CGCATGAGGATC	CATGCTGCCTCCCGTAGGAGT	M22Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Hair	CACACGTGAGCA	CATGCTGCCTCCCGTAGGAGT	F22Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Fcsw	GTTCGCGTATAG	CATGCTGCCTCCCGTAGGAGT	M43Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Fcsw	CCTCTCGTGATC	CATGCTGCCTCCCGTAGGAGT	M22Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Aptr	CAGATCGGATCG	CATGCTGCCTCCCGTAGGAGT	M21Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Pinr	GAGTGGTAGAGA	CATGCTGCCTCCCGTAGGAGT	M42Pinr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Plml	CGATCGAGTGTT	CATGCTGCCTCCCGTAGGAGT	M22Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Fotl	CATGGCTACACA	CATGCTGCCTCCCGTAGGAGT	M21Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Plmr	CGATGCACCAGA	CATGCTGCCTCCCGTAGGAGT	M22Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Fotr	CATGTAATGCTC	CATGCTGCCTCCCGTAGGAGT	M21Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Pinl	GAGTGAGTACAA	CATGCTGCCTCCCGTAGGAGT	M42Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Aptl	CAGATACACTTC	CATGCTGCCTCCCGTAGGAGT	M21Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Ewax	GTCTGACAGTTG	CATGCTGCCTCCCGTAGGAGT	F34Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Ewxr	CAGCTAGAACGC	CATGCTGCCTCCCGTAGGAGT	M21Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Uric	TCAATCTAGCGT	CATGCTGCCTCCCGTAGGAGT	M63Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Ewxr	CCGATGTCAGAT	CATGCTGCCTCCCGTAGGAGT	M22Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Ewax	GTGTGCTATCAG	CATGCTGCCTCCCGTAGGAGT	M43Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Urin	TCAACAGCATCG	CATGCTGCCTCCCGTAGGAGT	M63Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Fcsw	GTGACTGCGGAT	CATGCTGCCTCCCGTAGGAGT	F34Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Tong	TACTTCGCTCGC	CATGCTGCCTCCCGTAGGAGT	M53Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Tong	GTCTGGATAGCG	CATGCTGCCTCCCGTAGGAGT	F34Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Plmr	GGTCACTGACAG	CATGCTGCCTCCCGTAGGAGT	M34Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Nose	CTCGATTAGATC	CATGCTGCCTCCCGTAGGAGT	M32Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Nost	GTCTACACACAT	CATGCTGCCTCCCGTAGGAGT	F34Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Frhd	GAGGCTCATCAT	CATGCTGCCTCCCGTAGGAGT	F14Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Nose	CGTGATCTCTCC	CATGCTGCCTCCCGTAGGAGT	M31Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Tong	TCAGGACTGTGT	CATGCTGCCTCCCGTAGGAGT	M64Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Plml	GGTCGTAGCGTA	CATGCTGCCTCCCGTAGGAGT	M34Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Forr	CGAATCGACACT	CATGCTGCCTCCCGTAGGAGT	M22Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Nstl	GACACTCGAATC	CATGCTGCCTCCCGTAGGAGT	M41Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Pinl	ATACAGAGCTCC	CATGCTGCCTCCCGTAGGAGT	F12Pinl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Ewax	TACTTACTGCAG	CATGCTGCCTCCCGTAGGAGT	M53Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F14Tong	GATACGTCCTGA	CATGCTGCCTCCCGTAGGAGT	F14Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Forl	CGAAGACTGCTG	CATGCTGCCTCCCGTAGGAGT	M22Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Nstr	GACAGCGTTGAC	CATGCTGCCTCCCGTAGGAGT	M41Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Indr	GAGATGCCGACT	CATGCTGCCTCCCGTAGGAGT	M42Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Mout	ACGTTAGCACAC	CATGCTGCCTCCCGTAGGAGT	M12Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Frhd	CTTGATGCGTAT	CATGCTGCCTCCCGTAGGAGT	M41Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Ewxr	AGTACGCTCGAG	CATGCTGCCTCCCGTAGGAGT	F12Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Mout	CACATTGTGAGC	CATGCTGCCTCCCGTAGGAGT	F22Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F12Ewxl	AGGTGTGATCGC	CATGCTGCCTCCCGTAGGAGT	F12Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Tong	GCAGGCAGTACT	CATGCTGCCTCCCGTAGGAGT	M24Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Hair	ACACTGTTCATG	CATGCTGCCTCCCGTAGGAGT	M11Hair	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Kner	CAGCATGTGTTG	CATGCTGCCTCCCGTAGGAGT	M21Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Tong	GACGATATCGCG	CATGCTGCCTCCCGTAGGAGT	M41Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Kner	ATGTGTCGACTT	CATGCTGCCTCCCGTAGGAGT	F22Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Kner	AAGAGATGTCGA	CATGCTGCCTCCCGTAGGAGT	M11Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Knel	ATGTGCACGACT	CATGCTGCCTCCCGTAGGAGT	F22Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Nose	ACTACGTGTGGT	CATGCTGCCTCCCGTAGGAGT	M12Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Knel	CAGCACTAAGCG	CATGCTGCCTCCCGTAGGAGT	M21Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Nstr	ACTATTGTCACG	CATGCTGCCTCCCGTAGGAGT	M12Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Forl	ACACATGTCTAC	CATGCTGCCTCCCGTAGGAGT	M11Forl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Fotl	TAGCTCGTAACT	CATGCTGCCTCCCGTAGGAGT	M54Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Fotr	TAGCGGATCACG	CATGCTGCCTCCCGTAGGAGT	M54Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Nose	GCAGCACGTTGA	CATGCTGCCTCCCGTAGGAGT	F31Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M54Plmr	TAGATCCTCGAT	CATGCTGCCTCCCGTAGGAGT	M54Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Navl	AGCACGAGCCTA	CATGCTGCCTCCCGTAGGAGT	F11Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Fcsw	ACACACTATGGC	CATGCTGCCTCCCGTAGGAGT	M11Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Nstl	ACTAGCTCCATA	CATGCTGCCTCCCGTAGGAGT	M12Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M44Frhd	TAACAGTCGCTG	CATGCTGCCTCCCGTAGGAGT	M44Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Fcsp	AATCGTGACTCG	CATGCTGCCTCCCGTAGGAGT	M11Fcsp	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Indl	ATCTCTGGCATA	CATGCTGCCTCCCGTAGGAGT	F21Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M13Nost	CTTGTGTCGATA	CATGCTGCCTCCCGTAGGAGT	M13Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Mout	CGAGGCTCAGTA	CATGCTGCCTCCCGTAGGAGT	M22Mout	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Nose	ATGACTCATTCG	CATGCTGCCTCCCGTAGGAGT	F21Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Fcsw	GCATAGTAGCCG	CATGCTGCCTCCCGTAGGAGT	M24Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Plmr	GACAGTTACTGC	CATGCTGCCTCCCGTAGGAGT	M41Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Urin	GACGCAGTAGCT	CATGCTGCCTCCCGTAGGAGT	M41Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Plml	GACAGGAGATAG	CATGCTGCCTCCCGTAGGAGT	M41Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Indr	ATCTGAGCTGGT	CATGCTGCCTCCCGTAGGAGT	F21Indr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Indl	AGATCGGCTCGA	CATGCTGCCTCCCGTAGGAGT	F11Indl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Forr	CTATCTAGCGAG	CATGCTGCCTCCCGTAGGAGT	M32Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Fotl	ATGGATACGCTC	CATGCTGCCTCCCGTAGGAGT	F21Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Aptr	AACTCGTCGATG	CATGCTGCCTCCCGTAGGAGT	M11Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F31Urin	GCATTGCGTGAG	CATGCTGCCTCCCGTAGGAGT	F31Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M63Fotr	TATGCACCAGTG	CATGCTGCCTCCCGTAGGAGT	M63Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F21Fotr	ATGGCAGCTCTA	CATGCTGCCTCCCGTAGGAGT	F21Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Urin	GACGTTGCACAG	CATGCTGCCTCCCGTAGGAGT	M14Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M14Uric	GACTAACGTCAC	CATGCTGCCTCCCGTAGGAGT	M14Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Nstr	GAGTAGCTCGTG	CATGCTGCCTCCCGTAGGAGT	M42Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Ewxr	CTAGGTCACTAG	CATGCTGCCTCCCGTAGGAGT	M32Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Plmr	GCAATAGCTGCT	CATGCTGCCTCCCGTAGGAGT	M24Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Aptr	CGCGTAACTGTA	CATGCTGCCTCCCGTAGGAGT	M31Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Aptl	ATGTACGGCGAC	CATGCTGCCTCCCGTAGGAGT	F22Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Fotr	GTGTACCTATCA	CATGCTGCCTCCCGTAGGAGT	M43Fotr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M41Nose	GAATGATGAGTG	CATGCTGCCTCCCGTAGGAGT	M41Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Aptl	ACCTGTCTCTCT	CATGCTGCCTCCCGTAGGAGT	M12Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M12Aptr	ACGACGTCTTAG	CATGCTGCCTCCCGTAGGAGT	M12Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F24Frhd	GCTAAGAGAGTA	CATGCTGCCTCCCGTAGGAGT	F24Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M43Fotl	GTGTCTACATTG	CATGCTGCCTCCCGTAGGAGT	M43Fotl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M31Aptl	CGCGATAGCAGT	CATGCTGCCTCCCGTAGGAGT	M31Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Aptr	ATGTCACCGTGA	CATGCTGCCTCCCGTAGGAGT	F22Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Plml	GCACATCGAGCA	CATGCTGCCTCCCGTAGGAGT	M24Plml	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M42Nstl	GAGGCTCATCAT	CATGCTGCCTCCCGTAGGAGT	M42Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Labi	GCTATTCGACAT	CATGCTGCCTCCCGTAGGAGT	F32Labi	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Uric	TAGAGAGAGTGG	CATGCTGCCTCCCGTAGGAGT	M53Uric	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Kner	GCGACTTGTGTA	CATGCTGCCTCCCGTAGGAGT	F32Kner	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Aptr	CTACTGATATCG	CATGCTGCCTCCCGTAGGAGT	M32Aptr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Navl	CGAGTCTAGTTG	CATGCTGCCTCCCGTAGGAGT	M22Navl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M53Urin	TAGACTGTACTC	CATGCTGCCTCCCGTAGGAGT	M53Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Urin	CAGAGGAGCTCT	CATGCTGCCTCCCGTAGGAGT	F22Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Ewxl	CCGACTGAGATG	CATGCTGCCTCCCGTAGGAGT	M22Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Aptl	CTACTACAGGTG	CATGCTGCCTCCCGTAGGAGT	M32Aptl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Fcsw	GATTAGCACTCT	CATGCTGCCTCCCGTAGGAGT	M23Fcsw	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Knel	GCCTATACTACA	CATGCTGCCTCCCGTAGGAGT	F32Knel	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Ewxl	ATTATCGTGCAC	CATGCTGCCTCCCGTAGGAGT	F22Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M24Frhd	GCACGACAACAC	CATGCTGCCTCCCGTAGGAGT	M24Frhd	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M23Ewax	GATGATCGCCGA	CATGCTGCCTCCCGTAGGAGT	M23Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M22Glns	CGACATGCTATT	CATGCTGCCTCCCGTAGGAGT	M22Glns	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M34Tong	GTAGATGCTTCG	CATGCTGCCTCCCGTAGGAGT	M34Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Nose	CATATCGCAGTT	CATGCTGCCTCCCGTAGGAGT	M21Nose	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F22Ewxr	ATTCTGTGAGCG	CATGCTGCCTCCCGTAGGAGT	F22Ewxr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F32Urin	GGCAGTGTATCG	CATGCTGCCTCCCGTAGGAGT	F32Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Nstl	CTCGCACATATA	CATGCTGCCTCCCGTAGGAGT	M32Nstl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Ewax	TCAGCTCAACTA	CATGCTGCCTCCCGTAGGAGT	M64Ewax	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M32Nstr	CTCGTGGAGTAG	CATGCTGCCTCCCGTAGGAGT	M32Nstr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F34Plmr	GTCGCTGTCTTC	CATGCTGCCTCCCGTAGGAGT	F34Plmr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M11Urin	ACCTCGATCAGA	CATGCTGCCTCCCGTAGGAGT	M11Urin	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Ewxl	CAGCGGTGACAT	CATGCTGCCTCCCGTAGGAGT	M21Ewxl	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.F11Tong	AGCTCCATACAG	CATGCTGCCTCCCGTAGGAGT	F11Tong	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M64Nost	TCACTTCTCGCT	CATGCTGCCTCCCGTAGGAGT	M64Nost	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
+449.M21Forr	CAGTCGAAGCTG	CATGCTGCCTCCCGTAGGAGT	M21Forr	True	CostelloWholeBodySites	CCME	Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 60 years old. The health status of the volunteers  [...]
diff --git a/examples/costello/unweighted_unifrac_pc.txt b/examples/costello/unweighted_unifrac_pc.txt
new file mode 100644
index 0000000..286f135
--- /dev/null
+++ b/examples/costello/unweighted_unifrac_pc.txt
@@ -0,0 +1,426 @@
+Eigvals	413
+15.2678552674	12.5379464442	10.7620614122	4.98375343554	3.64552045564	2.8860140874	2.17162013227	1.9716247801	1.86305989527	1.59828020445	1.36096738808	1.30739246659	1.26252255302	1.22862270774	1.14382763588	1.07864393429	1.02780137544	0.966879276701	0.910768221296	0.892020402107	0.871048980939	0.821342885162	0.808906416305	0.778557463954	0.751127506338	0.746350996393	0.711372083815	0.691282493989	0.676514005333	0.660489934091	0.647257852477	0.622185956257	0.612261011996	0.603265036243	0 [...]
+
+Proportion explained	413
+0.122074583847	0.100247517917	0.0860483771442	0.0398477465227	0.0291478655472	0.0230752101409	0.0173632523546	0.0157641836603	0.0148961499447	0.0127790961738	0.0108816546017	0.0104532947483	0.0100945360404	0.00982348883488	0.00914550735497	0.00862432916031	0.00821781599226	0.00773071156797	0.00728207398149	0.00713217524421	0.0069644976322	0.00656707108798	0.00646763493708	0.00622497899991	0.00600566197061	0.0059674712455	0.00568779632576	0.00552716942206	0.00540908753858	0.00528096660777 [...]
+
+Species	0	0
+
+Site	413	413
+449.F21Plml	-0.179510749191	0.160900395023	-0.00570965213906	0.122334439759	-0.0162248971994	0.0530924605415	-0.0163681270466	0.0295047118664	-0.0228627210432	0.0194643931779	-0.0234020975229	0.00262342032849	-0.0106046436122	0.0430988298262	-0.0630887695702	0.00599339682177	-0.015245993975	0.00584946120947	-0.0273203016538	0.0585321079543	-0.0193853142291	0.0113800189557	-1.42047752944e-05	-0.0305962701531	0.0372562287277	-0.0382331347924	-0.0183695632125	0.0129618226604	0.0240291382408 [...]
+449.M22Pinr	0.0228821893392	0.126741711638	0.0271440495268	-0.127739135345	-0.0655730666726	-0.0409999396716	0.0930591748341	-0.0416917217096	-0.00656319363974	0.0246230231662	0.00677014688723	0.0612758058835	-0.0851472534354	-0.0440036946595	0.157352758593	-0.0805693976968	0.00644626237501	0.0278067611028	0.117551579422	0.0316687979704	0.097391526821	0.000599773734468	0.00762879627636	-0.0118059779527	0.0110565623068	-0.038459470733	0.011239792493	0.0279120201451	0.0348472026767	-0.0529 [...]
+449.M11Glns	0.183540331585	0.0665827817047	0.0149981843457	-0.180790814272	0.0458596183358	-0.000172025877953	-0.0201738850462	0.000766270524416	0.0172096746831	0.0063082185621	-0.119129938475	-0.0545045741645	0.0288978706878	0.0694659207831	-0.0305496533615	-0.0932699682326	-0.106903758724	0.0174357878118	0.0257274523207	0.105946908069	0.0205976160791	-0.027480744695	0.0234663648902	0.00573362184383	-0.0147648246135	-0.0360805239666	-0.0338647515378	0.0114979443109	0.0479358868198	0.040 [...]
+449.F33Fotr	-0.189814777693	0.14904689444	-0.138100278244	0.239620556398	0.028344444461	0.0482514718318	-0.0665537871953	0.0251146186602	0.0491962395075	0.081767299876	-0.0943117237678	0.0236499446234	0.00386986314745	-0.0306449523977	-0.0980194727268	0.0538497700739	0.028516911291	-0.0361966218797	-0.00249015611609	0.0128913294374	-0.0407913058004	0.0224865776793	0.0187852892454	-0.0175982222203	-0.000663421392733	0.0177019211402	0.0159452473051	-0.0551311979147	0.00859683279248	0.02798 [...]
+449.M54Plml	-0.205173121754	0.114582609172	0.0398627555447	0.07244766104	-0.0215930402801	0.0051090829957	-0.0906642558218	0.0285869469215	-0.116654759907	0.00562820798904	0.0157380444933	-0.0208269617433	0.0741017852091	-0.00238984001716	-0.045995903178	0.0104435434741	-0.00284559526274	-0.0330464037066	0.00932501864742	0.0499633018093	0.0300368640111	-0.019436192775	-0.0380850262703	0.00719156227655	-0.0303270559524	-0.0236433434132	0.0605309528317	-8.18034064438e-05	0.0122749821778	0. [...]
+449.F32Fotl	-0.124142214882	0.197819584616	-0.122694581868	0.140928479817	0.0352966233856	0.0716655692859	0.0544296565799	0.0267557836985	0.109567163896	0.0508974938797	-0.0440679986463	0.0134613552449	-0.0359740462395	0.0347234000752	-0.00829220947948	-0.051078144239	-0.0207346431171	-0.0333626596987	-0.0588630581847	-0.0437872224688	-0.0306100012562	0.0260098487854	0.0062432262279	0.0109848660848	-0.00162996679697	0.0177192761434	-0.00622323711894	-0.0456273036506	0.0296278351333	0.021 [...]
+449.M22Plml	-0.187907940136	-0.146385714479	-0.188015709799	-0.120087534466	-0.125465091547	-0.250210808173	0.00578373353921	-0.0397618882894	0.056800089084	-0.0215933988076	0.0494031627142	0.0134899471501	-0.0407513883933	0.00875268196689	-0.0541221871022	-0.062970371663	-0.0145023719949	0.0364081910321	-0.0224059696978	-0.0231793963707	-0.0370609121147	0.0077456029295	-0.0161000764137	0.0220401773928	-0.00530778288201	0.0174160459113	-0.0319220406769	-0.0503586998039	0.0107348713983	0. [...]
+449.M24Fotl	-0.135903719484	0.184445879892	-0.135213773324	0.188660177948	0.0223723764383	0.0969968486464	-0.0801677668945	-0.00270996157482	0.076175411141	0.0745898082588	-0.0441684516185	0.0517838025522	-0.00783505767962	-0.0517791698134	-0.0686286311582	0.0428387139248	-0.0276793072228	-0.0284287993027	-0.0409987951477	0.00333584305201	-0.0244750623233	0.00757089843103	-0.0139031111651	-0.0165299903565	-0.0278403913939	-0.0194038661382	-0.0130890057559	-0.0639870514078	0.0185326418962 [...]
+449.M21Glns	-0.0814511528085	-0.00568651768083	-0.145667548256	-0.133533259849	-0.00365061448338	-0.177001667338	-0.02174574843	-0.0208536025593	0.105945298346	-0.0878402342015	-0.0232803620565	-0.0428455921612	0.0954626560777	0.0290542342471	-0.00756540622114	0.0208561549509	0.0333508058741	-0.0284400818267	0.0243910847413	0.0505583974061	-0.0135957493666	-0.0197274389811	-0.0182207706598	0.0420919598436	-0.00408727435319	-0.0472197354884	0.0331173991293	-0.00444686875804	-0.01084725075 [...]
+449.M21Plmr	-0.248622159043	-0.0345018203617	-0.0996021905435	-0.0438472021975	-0.0983872474324	-0.223534029572	-0.00845468014266	-0.0388409803808	0.0345282580116	-0.00193366387288	0.0632299746811	-0.0172561216565	-0.00748987246948	-0.00514750193493	0.0281511635966	-0.00455080767455	0.00954535332664	0.0072664467796	-0.016038791028	0.00584575683644	-0.012544847559	0.0190659396107	0.0547884662494	0.0344382831543	-0.0153696026493	-0.00542304402154	0.0178675388376	0.0199905700986	0.021215553 [...]
+449.M23Knee	-0.11929889346	0.165384874511	-0.123996026279	0.0279026748222	-0.0221042143156	-0.0178807004934	-0.0362078246254	-0.057778403634	0.0498915058291	-0.0764200004167	0.00739690738962	0.0486760952001	0.0319390013285	-0.0125154233751	0.00376651783552	0.0810510392918	-0.0812462601453	-0.0266050314262	0.0823493720963	-0.0384841416332	-0.0387397884524	-0.0266103509761	0.021538675548	0.0134355020388	0.013930557362	0.00703265597612	0.0325703335501	0.0244081113094	0.0424041608073	0.01610 [...]
+449.M43Plmr	-0.211366228064	0.160804510335	0.00544133277503	0.103479762106	0.00322726986825	-0.0219012011303	-0.0984977520158	0.0114113442584	-0.0971302574201	0.0341446528978	-0.0269151088873	-0.0128750621196	0.0499541576648	0.0274312034022	-0.00723892764329	0.0136757483295	0.0459988909402	0.045123196071	-0.0313733339913	0.0134526293771	0.0257240629036	-0.00347956228355	0.0557268679638	-0.044561886078	0.016120523643	0.00685092042425	0.00921986106759	0.0289506043829	-0.0462847525549	-0.05 [...]
+449.M63Plmr	-0.125025207581	0.149060014638	0.000378216123617	-0.0145717942932	0.0173190252299	-0.00726746080693	-0.0216435293279	0.0357451784621	-0.110473108712	-0.0590094929922	0.0230570863319	-0.0261179257741	0.0501822052912	0.0167974904643	-0.0128378541923	0.0549496512786	0.0660642158968	-0.031852561265	0.043749742403	-0.0451629952323	0.0091743175261	-0.065821695644	-0.0088823313254	0.0361300009281	-0.0219153942392	0.0380496678084	0.0213079672561	0.0322004389669	-0.00884061817716	0.03 [...]
+449.M64Plml	-0.199810153428	0.129956087796	0.0154476269886	0.0575242405483	-0.00926085731499	-0.0628714557339	-0.0425005567401	-0.00626711331991	-0.0447308960178	0.027191770189	-0.0300530113703	0.010344559627	0.01675214995	-0.00476135432651	0.0297870852546	0.050534553738	0.0292808387717	0.0220841019401	0.0100289179227	-0.0605797700695	0.0606285354913	0.00294719279806	0.0117485348891	0.0335654522213	0.0103828294413	-0.0773680315219	0.0457157903901	0.0322555401099	0.00177389193463	0.017690 [...]
+449.F23Plml	-0.169396194858	0.171588002571	-0.0720168003033	0.0800154927305	0.00707316305096	0.00398806237713	0.0416228371917	0.0498773366747	-0.0304042946164	-0.019174241491	0.00968673797421	-0.0191389788859	-0.0411862324824	0.0193428350672	-0.0108654909004	-0.0260152392645	0.0247317138904	0.0168033485725	-0.00873614337585	0.018511715394	0.00316518962992	0.000543043619154	0.0414421501171	-0.00326157642724	-0.00620320642026	-0.014012121948	-0.00552705004871	0.0317830597196	0.007240006406 [...]
+449.M44Plml	-0.218021715122	0.132329080564	0.043308133209	0.0716239484997	-0.0293826288586	-0.0359538133583	-0.0931626988656	0.0244460592652	-0.108940400717	0.0174400485267	0.00231869650853	-0.00786626792821	0.0883809133422	0.0523075558456	-0.00670668911913	0.0319882091211	0.0373232242492	0.00305409453328	-0.00682419229135	-0.00507453131831	0.0472582151734	0.0237190137808	0.0468338925708	-0.0248742696732	0.0116661246151	0.0464206770936	0.0849588099156	0.0282667178346	-0.0402834055101	0.0 [...]
+449.F23Plmr	-0.195069136466	0.125816416887	0.0786829257692	0.0663810202945	-0.0409093952209	0.0223080979979	-0.0606754824718	0.00802497278049	-0.113628542779	-0.0404161263267	0.0290162970606	-0.0486015344444	0.0564458285415	0.0751668630833	-0.086305907852	0.00843546167069	0.0597110213529	0.0436355153201	-0.0140432942482	0.0579105438122	0.0323782793621	-0.03323330609	0.00802926349935	-0.0179613448181	0.0275906028572	-0.0310055777102	-0.0289882204593	0.0297619721148	0.0119092371481	-0.0029 [...]
+449.M23Nost	-0.0535424770638	0.130586491484	0.0695553358886	-0.135836133082	-0.00141589498417	-0.0495293907584	-0.0127426843274	0.0168254045883	-0.0635772760798	0.0697409799543	-0.0553966315288	0.160095738283	0.0461491203319	0.00493997711687	0.0609769086237	-0.0415856798549	-0.0349313568969	0.0229882486984	-0.0332031716643	-0.0508825617831	0.0305792258898	-0.0309780289961	0.0312761748214	0.0275985617153	0.0127323548891	0.0252059108991	-0.0172180768863	0.00623561979989	0.0705254327728	0.0 [...]
+449.M54Plmr	-0.189904019421	0.0888923186883	0.112458409843	0.0403432544819	-0.0321117551796	-0.0163155448	-0.0686690097636	0.0124839124144	-0.155464641067	0.0328022393557	0.0402002780295	0.00163469423309	0.0675903847398	0.0336762960076	-0.0277726499114	-0.0343229505985	0.0230009713233	0.0398353338429	-0.0120827979786	0.0046758650768	0.0332923385596	-0.0219378469455	-0.0477675331195	0.0132534437872	-0.00069849541468	-0.00437947734442	-0.00259913072916	0.0412106961979	-0.00763291686575	0.0 [...]
+449.M53Plml	-0.12645811983	0.150775475109	0.0118595391129	0.0280967908093	-0.0196118542186	0.0335560791816	0.0341044462837	0.0454447202164	-0.0336952801155	-0.0430997301059	0.0276803427331	-0.0270424612414	-0.0283327125607	0.0133125275489	-0.0385702038435	-0.0143510140666	0.0210124365998	-0.0002086243792	-0.0282026481994	0.0180452855687	-0.0790240263628	-0.081095801874	0.0132229633703	0.00718017863243	-0.0153234244601	-0.0652433208032	0.0866951971851	0.0804353916049	-0.0810744196054	-0.0 [...]
+449.M44Plmr	-0.181338561741	0.13866410771	0.0196675228915	0.0245505236348	-0.00163710695978	-0.0530176379239	-0.054085527823	0.0181493115994	-0.0635137721633	-0.0050690508807	-0.0445377767337	0.0231840198335	0.0355811281075	0.0334435600872	0.0638787641717	0.100431901232	0.0107055423816	0.0491086949967	0.0509666836922	-0.0267192875656	0.0459261649394	0.00596451044276	-0.00915105353975	-0.0143136464214	-0.0191487840963	0.00554755310562	0.0270091450829	0.0707879904642	-0.0281841617378	-0.00 [...]
+449.M43Plml	-0.177368488728	0.185229217828	-0.0710370487845	0.0733427454281	0.0118119287304	-0.0370932321036	-0.0534224058116	0.0679818420828	-0.0620725257566	-0.0228341529328	-0.0337442778562	0.00776684152407	0.0530518492127	0.0586477973021	-0.0169709046558	0.0483017317595	0.00616980879415	0.0279980855639	0.0155683250206	-0.0150653963453	-0.0477316642014	-0.0404734214249	0.00148507588389	-0.0246573544377	0.027940790953	0.0215341253138	-0.0136170677913	0.0701650999961	-0.0817960704533	-0 [...]
+449.M63Plml	-0.0880449396977	0.195632457877	-0.0563429887624	0.0118467104699	0.0194581123594	0.0150725034938	0.0233607587982	0.0033537201938	-0.0666941779619	-0.0550198179044	0.102747402613	0.0056850806786	-0.0507419792548	-0.0144096091121	0.0453818469513	0.0497039890171	0.0494122437894	-0.00358475262316	0.0363597977183	-0.0180734893687	-0.0292901061241	-0.0454136346416	-0.0493956786099	0.00527098096751	-0.0286219339929	0.0221397660841	-0.0322093612021	0.0159053394457	0.00287472883657	-0 [...]
+449.M53Fotr	-0.194435917003	0.122461312712	-0.158732954881	0.169371763413	0.0329658639362	0.00038561189425	-0.0943113777354	-0.0065152212184	0.0534723602701	0.0611407499247	-0.0311670878596	-0.0387888577447	-0.0311456379359	-0.0925330455432	-0.0150342671852	-0.00292734375938	0.011021594144	-0.0463439656926	0.0277193663896	0.00525627231733	-0.015395971797	-0.0160363038387	-0.0359139952449	0.0151205479248	-0.0353049515839	0.00633523293951	0.0255620654982	0.0528766915104	-0.0902755127592	-0 [...]
+449.F14Plmr	-0.187812212119	0.179540571482	-0.0958674373183	0.127881348581	0.0100379859399	0.0181032416285	0.00747525667167	0.0248723446988	0.0346163232846	-0.000585279322141	-0.0375510205498	-0.0218217098216	-0.0480382230627	-0.011617984726	0.00310073395744	0.0319292526168	0.0223413086879	0.0202415669671	-0.0175484870695	0.01889840024	0.000117194518105	-0.00942952508048	0.0119789655211	-0.0246900854099	0.0211680685924	-0.0232964432758	0.0492162370835	0.00899730635501	-0.0297586896954	-0 [...]
+449.F24Plmr	-0.177175665102	0.157461540814	-0.0383623784397	0.0810416615745	-0.00986792163051	0.0308042818052	-0.0301103399168	0.0563116517093	-0.0478068371192	-0.0651949979614	-0.0148067780348	-0.0143251298243	0.0454213252289	0.0479413104636	-0.0673059456699	0.021797300154	-0.0052732097743	-0.0304747865138	-0.00579387176426	0.0870728425202	-0.000394385485417	0.00474129596059	-0.00795057302306	0.000397127528378	0.0119661657272	0.00560589880956	0.00550110184469	0.049151900445	-0.057207879 [...]
+449.M31Plmr	-0.170069696609	0.0641762206453	0.130514179372	-0.0384963444818	-0.0469977310492	-0.0537188011115	-0.130050390385	-0.0183720206719	-0.14298822515	0.00286898723005	0.0275944152994	-0.016574812797	0.0769862490489	0.0570362234613	0.0220947540569	-0.0291622689728	-0.0478000992963	0.0965251820063	-0.0245848966832	0.0149731418184	-0.0409375248882	-0.0326813985891	0.0350164881159	0.0238015329952	-0.0131455220969	-0.0280960877352	0.0100904049656	0.0264531065637	-0.0196175341613	0.034 [...]
+449.F22Knel	-0.125642219359	0.054440582712	-0.138871060882	-0.0306514885899	0.0657672567771	-0.0399960324642	-0.00919626840903	0.0414450915394	-0.026238021361	0.0213267495576	-0.018913931034	-0.0559798592097	0.0429654583758	-0.0584892987963	0.12750478928	-0.0984008548049	0.0449241756757	0.0516429258827	0.0169545553794	0.0925986477578	-0.111613523871	-0.000540676103526	0.0175945821009	0.00093207044939	0.0184414371826	-0.00032681162846	-0.0248265278095	-0.00325354873807	-0.025418746422	-0. [...]
+449.M31Knel	-0.0685698748659	0.114054794311	-0.0746527191097	-0.0706933440004	0.0449494550806	-0.00850946835782	-0.0525935615317	-0.0171102828003	-0.017243242711	-0.0756126400103	0.0812497744166	-0.0708113937631	0.050067139475	-0.0459384103151	0.0264266965226	0.0478126855054	-0.0580353915968	-0.0463797528073	0.0928046568814	-0.0204122947441	-0.11304129706	-0.0764897992766	-0.0380940207777	-0.0222587081866	4.17254653993e-05	0.0303868784211	-0.0478891442603	-0.0379792986342	0.0009683448546 [...]
+449.F22Mout	-0.211758804134	-0.172221161364	0.358186760555	0.0484334343703	-0.0472532821071	0.0152449532288	-0.059769703368	-0.03672366659	-0.028276560053	-0.00270821215266	0.0124133760607	-0.0418440111484	-0.0434054095032	0.0330514403269	-0.0176217643859	0.00140794308382	0.0158951521118	0.0357376602154	0.0353745934814	0.0394164559245	0.0131968161939	0.0223296858644	0.0150205116019	-0.0313255205046	0.0504556669788	-0.0239198828946	0.0116628201255	-0.0498960466346	0.0241732623572	0.021600 [...]
+449.F21Navl	-0.133258249828	0.0600790203023	0.165441318502	0.00733831012149	-0.0206730968288	-0.01797947973	-0.019702433565	0.01138218486	-0.0915300040079	0.00867630047193	0.0559267107655	-0.0527649964094	0.0658179917724	0.098962640593	-0.0713191405756	-0.0398435159405	0.0164207177185	0.074191987604	0.00456410480007	0.00743687832349	-0.0534693024057	-0.00507707477299	0.0543567479315	-0.0609535265774	0.0910480411124	-0.0164713787917	-0.0188187205276	-0.00606542955761	0.014211297678	-0.053 [...]
+449.F22Plmr	-0.185611007071	0.175726685163	-0.0149352183462	0.0498301523534	0.00677044039402	0.0183068470672	0.0314141221924	0.0406715930148	-0.0529251434272	-0.000748418827848	0.0504187504361	-0.0370724404221	-0.00236184977413	0.0206248404501	0.0394720224026	-0.0486740759777	0.0121683955404	-0.0682381439689	0.00114760623895	0.0358413627413	0.0430824798522	0.0108221561119	0.0126401479676	0.0435142381657	-0.00177901040386	-0.0064511276825	0.00254328770114	0.0403737938857	0.0449262269778	- [...]
+449.F12Plmr	-0.221424984433	0.132393959865	-0.0160044973073	0.108140655367	-0.00863649064777	-0.0288380731149	-0.0824281268967	-0.00326981684596	0.00562765868167	0.0655065818758	-0.0664598676746	0.0207498877912	0.00287109473975	-0.0100256399048	0.0268752878197	0.0704744530216	-0.00979384295023	0.0339563324093	0.00151651327939	0.0214773778224	0.0571847693648	0.018915163267	0.041803548345	-0.0266977182493	0.0243892158178	-0.0756117973298	-0.0298393952411	0.0343444339728	0.00295866587241	-0 [...]
+449.F22Indr	-0.166086814209	0.180686633742	0.000319788374454	0.0573785006185	0.00690758599678	0.0183863671797	0.0292656540604	0.042123110003	-0.0703387001124	-0.0677233071198	0.0447888167726	-0.0473445968535	-0.0243084989422	0.0472413756503	-0.0222443534786	-0.0294954390921	-0.000947541846315	0.0445827157682	-0.0172523740117	0.0651669298167	-0.00392795377888	0.00455493508756	-0.0117224881988	0.0134518714586	-0.00336581094779	0.0305582979916	0.0177042745622	0.0161482808235	-0.026522942739 [...]
+449.M31Plml	-0.147044673028	0.103715434456	0.0930254655136	-0.0406156715941	-0.0120435959408	-0.0374193397126	-0.0710440101431	0.00461939357081	-0.118100726804	-0.0165412319343	0.045377970144	-0.0421674556528	0.0689097298213	0.0168059753023	0.0172655900741	0.0221626091138	-0.0143656700429	0.0112486143686	0.00890374743716	0.0260345396682	-0.0535155457075	0.0110889605287	-0.0420426424096	-0.043650789654	-0.0410247639844	-0.0576240042855	0.014157381973	0.0211265005531	0.0147860452364	-0.013 [...]
+449.M31Indr	-0.205889555005	0.0934723543447	0.10760263905	-0.00326150687356	-0.0463021669488	-0.054599476383	-0.0352203096081	0.0133757368661	-0.098921025856	0.0518554574285	0.0459891040014	-0.0328487888048	-0.0409269113119	0.0211481377746	0.0650646257745	-0.0542387106035	-0.0646385682029	0.0706421069791	0.0139670968872	0.0381901470827	-0.0104547485231	0.0108405439027	-0.0457344726007	-0.0381388145222	0.008591511981	-0.117839834606	0.0312965464654	-0.0020371809387	-0.00259086382772	0.014 [...]
+449.F12Indl	-0.0912100541004	0.186826812547	-0.0482016928481	0.0249971929338	-0.0176290876358	0.0392818395384	0.0025900651047	0.0389138392912	-0.0233339538085	-0.046761636274	-0.0648909530458	0.0423729738845	0.0211805799268	0.0530427186393	-0.0269633654009	0.0182553646349	0.013626195213	0.0582904842113	-0.0154981905228	0.0457306007766	0.0205985293365	0.0200525688688	-0.0202175058092	-0.0270271750506	-0.012767893216	0.0700798715396	-0.022038860737	-0.0333303962422	-0.0482419472572	-0.0182 [...]
+449.F12Plml	-0.20926946971	0.149867373833	-0.0798261488899	0.109078315142	0.02449669248	-0.0176867905465	-0.0697248993457	0.0229372867199	-0.00437024114641	0.0433171727603	-0.0443583592592	0.0155299057851	0.0511573484499	-0.0232418147145	-0.00376441734896	-0.00253681706158	0.0124773215054	0.0150009360208	-0.0472729632308	0.0361525708813	0.00625174216718	0.00553292187355	0.00888264550774	-0.00616638436441	0.00896938338982	-0.00390144530263	-0.0131133348916	0.0145551064465	-0.0264331220995 [...]
+449.F21Fotl	0.296335834583	-0.143058020136	-0.00180926221968	0.0984354651691	0.00373318628023	0.00888962292379	-0.133843757856	0.0720021767439	0.188790527895	0.042468219973	0.1427691443	0.116926284303	0.0726188372272	0.138167152999	0.0851301520857	0.028923007915	0.134055387132	0.00750398204843	0.0281423341944	0.0526990015517	0.0107908764215	-0.0818229637469	0.00321762069396	-0.00798659815896	-0.0297156808643	-0.00289479328182	0.059304115644	-0.00225225385593	0.0283960003511	0.04497404196 [...]
+449.M32Mout	-0.21705766867	-0.11255902331	0.306621647235	0.0400651866289	-0.101275644257	0.00418921355059	0.0121520056232	-0.0523857577338	-0.0196876389578	0.0523258534189	0.0758898312358	-0.0657521246606	-0.0455603767138	0.0258059420044	0.0279052836494	-0.0387428395275	-0.0134932649208	0.0753969172578	0.0186302865329	0.0652974321293	0.0159145711785	-0.0120349061044	-0.0028500009077	-0.0275872367277	-0.0272039365749	-0.0071916209749	0.0386480822535	-0.0036523656511	-0.0027901942835	0.025 [...]
+449.F12Pinl	-0.0480918162255	0.172564199148	0.0120206680611	-0.0160121049963	-0.0696482346779	0.0203916794774	0.129846669945	-0.00217851026579	0.0422388215018	-0.0844000739202	-0.0297519787157	-0.0611900154689	-0.0920902073996	0.037454398504	0.0714724595855	0.0172726490106	-0.0295596703897	0.00624602395923	0.0396431912017	-0.0115306734204	0.0291053783567	0.0312596919208	0.00789213996325	-0.0201024503638	-0.00973022950541	-0.025715693505	0.0131968077832	-0.0153874785869	-0.0557513939612	0 [...]
+449.F12Nstl	-0.0307977025059	0.0385085303593	0.0412689973236	-0.0457931943199	-0.0371036746736	-0.0137083027803	0.0850381906631	-0.0333498063789	0.00700317448964	-0.0313649532463	-0.0791937116657	0.0291414289732	0.000723853055004	0.00181044505722	-0.000781495557289	0.0239621202798	-0.0523834574242	0.0146169778029	0.0721628192908	-0.0858701984133	-0.0895597814876	-0.00383109772598	0.0561549333884	-0.0803483289014	0.116488063532	-0.0256513468512	0.0440916863713	0.00529577912889	-0.01527411 [...]
+449.M21Indr	-0.235244873321	-0.105589255443	-0.00330431171334	-0.0900944005	-0.134016443796	-0.22683989437	-0.0672173315147	-0.0410215183222	0.0080858607912	0.0199347426846	0.0258294589968	-0.000421977853281	0.0445124264062	0.00957093991334	-0.0239414629122	0.018147118261	0.00268425213767	0.0151815176888	-0.0224147896145	0.0153947742874	0.0213018648508	0.0292321705942	0.0824724223668	-0.0131031132721	0.0165196666485	0.00419492891257	-0.015519909643	-0.0166640751712	0.0133761731191	-0.035 [...]
+449.M21Mout	-0.187342102369	-0.147446966471	0.296311173965	0.0124476343269	-0.0900283523995	-0.0480739309509	0.000110185598564	-0.0484153019715	0.0208563991376	0.042395918362	0.00503622298983	-0.0582315054118	0.0258687442904	0.00599544269134	0.0197322653378	0.0557902105958	0.00617281133839	0.0726343098042	0.0155586396339	0.0746225601265	-0.0169584859652	-0.00304424110465	0.0838651200206	-0.0544198544265	0.040671154225	-0.0267219317946	0.047313168922	-0.0353180613364	-0.00556596661946	0.0 [...]
+449.M42Indl	-0.211489447985	0.11504434601	0.0822123575561	0.0351115383173	-0.0110157237501	-0.0620227716662	-0.0423579537099	0.0272624321741	-0.0972009204847	0.0124815907957	-0.00343450745176	-0.0475293879126	0.00958404722642	0.0495263223347	0.0159787783885	0.0437839733972	-0.0172960343737	0.0557438106918	0.0397658744429	-0.032173531237	0.0352924100092	0.0406353387618	0.00148588610772	-0.00818617978168	0.0222857047946	-0.0428442652509	0.0113219779687	0.0543963780869	-0.0417228970414	-0.0 [...]
+449.M21Indl	-0.239892229836	-0.107266191939	-0.0375876885733	-0.0911267820517	-0.143227451114	-0.253484019124	-0.0655484276319	-0.0508193112616	0.00529745753434	0.00519187191732	0.0480877576465	-0.0190824664556	0.0467989003326	0.0061997734772	-0.0386650860903	0.00853710020966	0.0115439830921	0.00963408680887	-0.00787381442461	-0.00930317199367	0.0305140808834	0.0450869766795	0.0597293461525	-0.00169916993717	0.0104140530912	-0.0402979559863	-0.0314241101936	-0.0301886362929	0.04158171992 [...]
+449.F32Plmr	-0.184662208949	0.17865881082	-0.0455560135676	0.0893210494134	0.00612125547534	-0.0245380353942	0.0608173624693	0.0380543823161	0.0205742163744	0.029935068183	-0.0300888962823	0.0387179158754	-0.121076927808	0.0234617272771	0.0261255769472	0.0265184458548	-0.00608304257352	0.0140142865856	0.0151303802546	0.014419188956	0.0467566350603	0.0161280799661	-0.0213077834922	0.019251876905	0.0220099098821	0.0374218533408	-0.0314285073767	0.0307353352397	0.0255071136916	-0.0105162192 [...]
+449.F31Mout	-0.199730430885	-0.151900720092	0.33250274357	0.0339103803509	-0.0708251173258	0.00396657533938	0.0238514826189	-0.0476904984075	0.00974914256565	0.0635272975108	-0.00206805345894	-0.00146499412831	0.0160506265767	0.0276707240042	-0.00507378897104	0.0242457783811	0.00962558410999	0.0845322807004	0.0337010420189	0.0334307197653	0.0967352408601	-0.00442530141325	0.0289416422711	-0.000573260389751	-0.00149986775972	-0.0194566233489	-0.0241578196011	0.039342619996	-0.008552377020 [...]
+449.M42Frhd	-0.0519580017921	0.153945343881	0.0820229642408	-0.103204918518	-0.0418704694851	-0.0216707542376	0.087971741986	0.0680535218853	-0.0797360609939	0.0126194290263	0.0403729272118	0.0319797129021	-0.0716092938714	0.122732349088	0.0222555465895	0.0168761561894	0.0169742471928	0.0383281882194	0.00459872069542	-0.0372496335865	-0.0261796992086	-0.014547381394	0.0099516393718	-0.0163392298511	-0.0159947452938	0.0413652031464	0.028058677049	0.01579570711	-0.022027507528	0.0193506508 [...]
+449.M21Nstr	-0.209044781936	-0.171666599362	-0.0828888910585	-0.132147058686	-0.143773428809	-0.253578908682	-0.0327296423966	-0.0266519806414	-0.00916631868887	0.0127903881531	0.0384099189429	0.0280031006173	0.0441202799705	-0.00692209781833	-0.028139398853	0.00900159199135	0.0200307846607	0.0125362289293	-0.0240275920957	-0.0285328905912	0.0167227584632	0.0222882036011	0.0574969877267	0.0184501665	0.00195962559887	-0.00456173061565	0.0348364476821	0.0288008684723	-0.00911252011599	-0.0 [...]
+449.M21Plml	-0.231602250487	-0.138570589252	-0.147622961495	-0.0775305501218	-0.126219922145	-0.236075746096	-0.04148439328	-0.0448583593802	0.0117812180104	0.0238006775689	0.072924010232	-0.00788819287881	-0.00796531503142	-0.0088162502771	-0.00123454502494	-0.0532924431201	-0.0421649241583	0.0525217844106	-0.0678010793763	-0.0239929452581	0.000769375834841	0.0177795054625	0.0505367687412	0.0307994165228	-0.0168757463386	-0.0151049657626	-0.0090492672589	0.00558853293429	0.0350071976232 [...]
+449.F32Nstl	-0.120575459149	0.120535729615	0.0744533046732	-0.0801471519922	-0.0377332165471	-0.0439415753483	0.090976576139	-0.0180158345755	0.0179148397708	-0.0077903264181	-0.000959457212903	0.0218275513299	-0.0986961917295	0.00930887751188	0.127412706132	0.00597569113624	0.0371787238438	-0.0548815309801	0.00153728712011	0.00510636377302	0.0445937058847	-0.0166346961334	0.0192911812188	0.00787784526817	0.0209578384814	-0.0522851890385	-0.0323986992039	0.0502977385078	0.0190914454706	- [...]
+449.M21Forl	-0.227269725968	0.0753971796869	-0.0904070033654	-0.00587876993606	-0.045774442447	-0.185969230401	-0.0434523309107	-0.017789943164	0.0102974857765	-0.019785805772	-0.0299952423241	0.0324617166407	0.0448451749775	-0.00617746413381	-0.000947628842238	0.0515928252507	0.0591047243113	0.0273735179053	0.00659628457873	0.0115658962276	0.0482037094681	0.0224236575736	0.0435068752514	0.0578375288451	0.00106986096697	0.0697003240454	-0.0162999796571	-0.0330794505736	0.00723917610859	- [...]
+449.M42Plml	-0.177299047751	0.169608272304	0.0245466052116	0.051737592675	-0.00147352320083	-0.0165609584266	0.0102026482022	0.0532419925188	-0.106952490116	0.0478054902945	-0.00221486244989	0.00975569993458	-0.0335214118422	0.0548616300185	0.0532679099652	0.00508926326915	-0.00554535363412	0.0678226014896	-0.0265198386246	0.00131015532777	0.0596872750047	0.0616296515683	0.026461320777	-0.0221986292814	-0.00319479587368	-0.0321101192902	-0.01777631243	0.0143722264512	-0.0338242957658	-0. [...]
+449.F32Indr	-0.146276606525	0.148003705384	0.0503514989416	0.0482982924457	-0.0211596781834	0.0366199711945	0.152767567603	0.060473824998	-0.0135184605351	-0.0261840083782	0.0707235580575	0.0125616973386	-0.0445664561645	0.0341549416871	-0.00526282988443	-0.0476802534844	-0.000165173803695	-0.00184970478607	-0.0710240734295	0.0338820546162	0.061101249448	-0.0241775917593	0.040924278998	0.03099700561	0.0656281885492	0.0294104699033	-0.00371881760407	0.0666301927632	0.0212361090417	0.01859 [...]
+449.F32Nstr	-0.0415114797056	0.135723743744	0.0681421100411	-0.106512247735	-0.0309590912574	0.00845878307525	0.138195839619	0.0343304209955	-0.0392203505072	0.0208933615782	0.0540129095078	0.0531637496871	-0.117456110773	0.0640692101702	0.0587317128235	-0.0236179002926	0.0627026936238	-0.0111371357366	-0.000757738498746	0.00675783023065	-0.00651289743163	-0.0717122046804	-0.0223871072716	-0.0128146310861	0.0185559652193	0.0190708914919	-0.0591987500793	0.0498001138062	0.0266310884939	-0 [...]
+449.F32Forl	-0.0401648965922	0.160125795326	-0.0339368160306	-0.0269021603337	-0.0117783548373	0.0118277012844	0.158417216189	-0.00213869617002	0.000603013085114	-0.0444622660647	0.0283474596781	-0.0114836168061	-0.0396449885606	0.0304286678287	0.000144936293477	-0.133272809142	0.0439317203394	-0.0109073077081	0.0474222621256	0.0509892325957	0.030147189652	-0.00229468979738	-0.00929958225736	0.0175644415619	-0.0104461698834	0.0386494935675	0.0116192791988	0.0440610826185	0.00011129269709 [...]
+449.F32Mout	-0.208807709737	-0.126462281797	0.329849067816	0.0182013273653	-0.0671032565677	0.0076932038224	0.0111830146984	-0.0609006623151	-0.00899691485184	0.0513687076192	0.00839768459418	-0.0410025948617	0.0163784488313	0.02572992319	0.0116977292284	0.0310363955918	-0.00238746471778	0.0860125812241	0.0143770047156	0.0512774035861	0.0889670773228	0.00530910818621	0.03214315131	-0.0278338898248	0.0111206181512	-0.0321022436479	-0.0282411123031	0.0167257176624	0.00630139678098	-0.00581 [...]
+449.M22Forl	-0.198911058061	0.00846535783657	-0.197591376311	-0.0462190022607	-0.0810300962591	-0.201145806287	0.0175603416178	-0.012118253952	0.0701448480125	-0.0351831031629	0.038705080609	0.0297197517478	-0.0321256381644	0.000361686213631	-0.00281808578913	-0.0311303147005	-0.0342311542758	0.00313633715589	-0.0473066956849	-0.00287942888923	-0.0410848682003	-0.0243003489158	0.0354069673822	0.0520782048847	0.0119908262343	-0.00647380781904	-0.0137318612402	0.0166681749855	0.01815613885 [...]
+449.F32Indl	-0.149130436304	0.166281222394	0.0226177972157	-0.0075601396217	0.0127565965479	-0.0281623548124	0.0702842964963	0.0249026114226	-0.0895980857164	0.0253551821979	0.0327716879916	0.0288305261148	-0.0531000483158	0.0260103590623	0.0878479534576	-0.0259759948613	0.0823828892038	-0.00214680190871	-0.0152087441096	-0.00708605181754	0.0572885581323	-0.0359471715046	0.0368565274139	0.036624153387	-0.00464346689091	0.0518214061863	-0.0530977518353	0.0673037990881	0.0732007698443	-0.0 [...]
+449.M22Indr	-0.222435129332	-0.0215014963779	-0.0901721866274	-0.0334295065469	-0.112153199218	-0.205854241313	-0.00332471526218	-0.0177404404111	0.047328492092	0.0163610758123	0.0334110389675	0.0163533089472	-0.0591497071371	0.0312453081474	-0.00644630265486	-0.00376465032552	0.0217423985284	0.0369660527727	0.00402560062706	0.0021130332808	-0.0105644109211	-0.0259764065966	0.0470564574199	0.0158139725616	0.0289996687534	-0.0108822788096	0.0461498894722	0.0337804466738	-0.0148180318392	0 [...]
+449.F32Plml	-0.170912066707	0.15133503927	-0.05063828922	0.0783030507276	-0.0209253656128	0.0127645509975	0.0897562570021	0.040605907127	0.0440974135524	-0.0315583129033	-0.012771847735	0.021064203681	-0.0843240082858	0.0642864199542	0.0439994037145	0.00797933980119	-0.0405192451108	0.0574597248632	0.00581434606666	-0.00467952110513	0.01795732295	-0.0152153102059	-0.0122332398686	0.0316480150698	0.0147500820828	0.0197569025283	-0.0382453863681	0.0742147349589	0.0279290455172	-0.041768264 [...]
+449.M21Forr	-0.238909942556	0.0454020463427	-0.0842922237527	-0.0124631719874	-0.0675057972671	-0.194887197244	-0.0142311893995	-0.0159825438162	0.0193474348285	-0.0129479547294	0.0280463382521	-0.012188803129	-0.0166158639355	-0.0116975063321	0.028589784113	0.00489676784335	0.0492906977439	0.00642285992002	-0.0190949438216	0.0202351073229	0.00177138008847	0.0155261297537	0.0585035332137	0.0373591760567	-0.00628757518114	0.0603935014515	0.0226625440144	-0.00982791535551	-0.00924463282727 [...]
+449.M22Mout	-0.204602903554	-0.126805354826	0.22474968717	-0.0334761077791	-0.111973783039	-0.0745536916323	0.0146683368231	-0.0391211180247	0.0398137992857	0.0628694620488	0.0583973711163	-0.0601279563432	-0.0520424535226	0.0111392586985	0.0602682656781	-0.0155414310195	0.00738853867107	0.0473898050065	0.0205965253798	0.0815558834538	0.0118342361494	0.00941766556684	0.0410978161769	-0.00582749688949	0.00565793058522	-0.00923172768834	0.0304883246422	-0.0351507598984	-0.0310132935278	0.0 [...]
+449.M42Mout	-0.22774020745	-0.192765976063	0.33020442755	0.0790957870569	-0.0569387685214	0.00663620113395	-0.0705865644715	-0.0479097363349	-0.0508738889582	0.011020473844	0.0161083182892	-0.0688238185871	-0.0162873509464	0.0375429093983	-0.0168808311907	0.00816615766137	0.0557851010854	0.0598900952347	0.023032951347	0.041130985212	0.0257346453247	-0.0074054264177	0.0490294575452	-0.0604270740252	0.0547068795341	-0.0278106213637	0.0424486715407	-0.020192515322	-0.0176956287444	0.0365041 [...]
+449.M53Fotl	-0.181063680442	0.123164401891	-0.166064512026	0.20746816367	0.0332876042428	0.0150601899786	-0.0905831681149	0.00769113613378	0.0696399914806	0.0772161516075	-0.11165477235	-0.00661089224741	-0.0395966627521	-0.0703830420087	-0.0637027343337	0.0674206226623	0.00513060701456	-0.0292550376889	0.0419302659813	-0.00421054829167	-0.0169172551279	-0.00744682341951	-0.0350732891799	-0.0407583216717	-0.0161214051567	-0.0251663036281	-0.0219508154099	0.00369198437293	-0.0440071362436 [...]
+449.F33Plml	-0.174122194016	0.205547806258	-0.110185479695	0.178132029798	0.0386154290351	0.0262566406207	-0.0291650967595	0.0396687953977	0.00420412424835	0.0617098101012	-0.0974006450711	0.0759667343161	-0.00543242377621	-0.00927991132606	-0.0740683863819	0.0741729628673	0.0488970567639	-0.0249101018591	-0.0213383675926	0.0304798962149	0.0231385539401	0.0388999892828	-0.011249268182	-0.011883190723	0.00503144775616	0.0363739172706	-0.0346051357514	-0.0296737050974	0.0642721033507	-0.00 [...]
+449.F31Fotr	-0.139315247143	0.171744626297	-0.175065768839	0.224055936806	0.0074122305135	0.0569852873067	0.0121856795105	-0.0284220580664	0.0810191317763	0.0898147098359	-0.0428232676493	0.0371286591318	-0.0759849696448	-0.045142819415	-0.0588554443202	-0.0204883714196	0.0237003496259	-0.0594714226457	0.0153776471855	-0.0340174115007	-0.0104128715918	0.0584350791275	0.0637521235118	-0.0198448154917	-0.00837145404574	0.0119962259487	-0.000208896625769	-0.0323246453972	0.0131331784262	0.0 [...]
+449.F32Nose	0.108457896135	0.0821887053235	0.0967696775384	-0.109461432051	-0.0653648612589	0.056983164332	0.129330222588	-0.00785898290386	-0.00437795770314	0.00598925073133	-0.0636022146098	0.0478281595812	-0.00225169293578	0.0135809706007	-0.0487677674898	0.00299913717996	-0.0566013823789	-0.0372002511459	-0.031193499489	-0.0689464890079	-0.0713746578024	-0.0278662564497	0.0115792189899	-0.0192502657868	0.0275037077085	0.00813129946323	-0.0250131397139	0.0327337790792	0.0256712936943	 [...]
+449.M53Fcsw	-0.08786800301	-0.374702686024	-0.288979891408	-0.0352674660124	-0.0359606705665	0.0405376582472	-0.00898510576226	0.0030448569178	0.0262847054881	-0.0335202021964	0.0745271892736	0.0940048462917	0.0383459550202	-0.000199302910067	-0.0830753423544	-0.037954358201	0.00412894298559	-0.100093126159	-0.0112084135312	-0.0313633048632	0.0777356906845	-0.0210906689158	0.00025868701804	-0.0599606690069	-0.0962584477743	-0.0126654719432	-0.0332456459374	0.070482093541	-0.0930661823453 [...]
+449.M14Fcsw	-0.0977493565075	-0.410466219006	-0.309904480124	-0.023787465516	-0.0227814886871	0.154013950167	0.037182277116	0.0265317641805	-0.0930752637802	0.0242654009418	-0.0263578143834	-0.0290453630657	-0.00200726170568	0.0380914753946	0.0173685363316	0.0167056618005	0.0211339255547	0.0282729792295	-0.0275744267508	-0.0224403777608	-0.0158798521769	0.00553923739449	0.00794553833033	0.0753815149437	0.0089753519708	-0.000255900371107	0.00225030728487	0.00224334306602	0.0231453957605	- [...]
+449.M33Fcsw	-0.0914977770995	-0.416869132929	-0.299558432901	-0.0288813161848	-0.0106569715954	0.157949704127	0.0283835265698	0.00385267307868	-0.0605582726048	0.0153247998	-0.0197919976639	-0.044710536339	-0.0418841123895	0.0116760551104	0.00320921064768	0.0376946155353	-0.0103631349593	0.0265286199454	0.00644031702108	-0.0223944655582	-0.000508085941155	-0.0207884856179	0.0202242759072	-0.030355433958	-0.0488475172709	-0.0152053027054	-0.0185949073671	-0.01508664984	-0.000232081005618	 [...]
+449.M13Fcsw	-0.107340418762	-0.411153114676	-0.308355877504	-0.0201889609098	-0.0315881589378	0.167618503062	0.0230500498782	0.010977679458	-0.0878668975812	0.0172761751953	-0.00473900652619	-0.00753453115908	-0.00189306032524	0.0225212494446	0.0202370623766	-0.00729188530677	0.0256450206801	0.0335322216182	-0.00142113484425	-0.0334365427674	-0.0127912011774	0.00355092773827	0.0042739270469	0.0454466976694	0.0213386054517	0.00116738664862	-0.00323957881414	0.00780806337835	-0.01291215402 [...]
+449.M63Fcsw	-0.0741251927186	-0.393598345488	-0.300935280323	-0.0543776042783	0.0196507060286	0.116329506727	-0.0397480548468	0.00368391680053	-0.0699173588711	0.053881916912	0.0262887699292	-0.0323611800671	-0.0200235268022	-0.00656035961054	0.0196421920967	0.0571466844193	-0.0158604694336	-0.0068507105361	0.000281631770245	0.0141328524067	-0.0168983088195	-0.0110639839703	-0.0278812417665	-0.0286546967077	0.0580600864231	0.0266046505316	-0.0097409779366	-0.0631496427027	0.0589684621662 [...]
+449.M24Fcsw	-0.12137588059	-0.364651767216	-0.262871302046	-0.101467000475	-0.0368265478771	-0.0585971219669	-0.0233995524024	0.00639351807666	0.0150043336253	-0.0239496401369	-0.0306016150345	0.00869638442748	-0.0237880127461	-0.04274607322	-0.0877899991148	-0.0845375631427	-0.0123982112477	0.0450465680607	-0.014655264671	-0.0448780531004	-0.00514383877312	0.0523324379857	-0.045300158882	0.0514650597635	0.0334897105398	-0.056084299382	-0.0324112600212	0.00856646321805	-0.0411279317107	0 [...]
+449.M54Fcsw	-0.073576399109	-0.349901543784	-0.266878369739	-0.0157281425088	-0.0332452885341	0.0470991210931	0.0138887899516	-0.0130653106	0.0200939686404	-0.0455126032572	0.0476196406536	0.117544333948	0.0267298354015	-0.0217327485291	-0.104935393672	-0.0626743879372	0.00478391849501	-0.0838839525596	0.0290292714502	-0.0399669217281	0.0593846700976	-0.0232711765592	0.00627336576641	-0.0597139431915	-0.113657059005	-0.0282343573102	-0.0177527323981	0.0906933246824	-0.111570228442	0.0056 [...]
+449.F21Fcsw	-0.124745130135	-0.417939374379	-0.233393051898	-0.0309269886756	-0.0162712512983	0.133074972584	0.0206289156013	-0.00182903580103	-0.063312483358	0.0128521442648	-0.0468694473149	0.0124987301561	0.0159676043198	-0.0351901554236	0.122240577583	0.0674408425181	0.0336004970472	0.014957540282	0.0269013953445	0.0248572093801	-0.0479282105137	0.0814400251299	-0.078320708317	0.104945119879	0.0783431909106	-0.0172569501462	0.0754337839085	0.00215123436433	0.0239326162953	-0.05434191 [...]
+449.F22Fcsw	-0.107915579005	-0.426434216255	-0.287210493877	-0.0430984344589	-0.0137851413557	0.106663136393	0.026645776532	0.0154948329268	-0.0489163055527	0.0167925571167	-0.0592359638742	-0.038921945455	-0.0103489665468	0.0103611993034	0.0441725462388	0.0628661350984	0.0243228171545	0.0172296517012	0.0122121087408	0.0279686673682	-0.0665636937481	0.0696278279962	-0.0555304393419	0.107850295001	0.0851615591381	-0.0202604275324	0.0613940409948	-0.00770976325801	0.0129616821942	-0.010419 [...]
+449.M31Fcsw	-0.103489471565	-0.375140414315	-0.256180208606	-0.0806846501711	0.0123706708183	0.0177226889655	-0.0364398688148	-0.00171370752243	-0.0320426939804	0.017439908109	-0.0334062363326	-0.0662083252361	-0.0440538918454	-0.0214821682685	-0.0189974139022	-0.00399938445867	-0.0624648090123	0.0605916526112	0.0129484177567	-0.00121058450679	0.00220805586916	-0.0124842248688	-0.0227708771528	-0.0561108282233	-0.0205774973271	0.00114899290453	-0.0495376705848	-0.0120768198856	0.00849885 [...]
+449.M22Nstl	-0.179084163532	-0.176966320289	-0.224780772789	-0.126787040308	-0.122841591714	-0.243691119111	-0.0206892381982	-0.03366155285	0.0324638706129	-0.0528833942112	0.0229917321894	0.0565860520886	0.0146049913712	-0.000377485496615	-0.0877967161894	-0.0149627776471	-0.016262057961	0.0260916724599	-0.0522519427231	-0.0400843192852	-0.0171020205198	0.0121387982067	0.00612811662042	0.0144165939046	0.0200458004623	0.0139801155837	-0.0206649400563	-0.00136682618549	0.00718584531731	0. [...]
+449.M22Indl	-0.204156396956	-0.112860757269	-0.191183400354	-0.0853390317341	-0.128536047646	-0.214392510795	-0.0153726324818	-0.0443384071796	0.0542315885743	-0.0104600557077	0.0419469624349	0.00647999542664	-0.0422686183409	-0.00741292059202	-0.042090699326	-0.0550405028589	-0.0124879924372	0.0211916574851	-0.0554612162225	0.0152000587834	-0.00458187374367	0.00375398882372	0.0254754307949	0.0064281861301	0.00174694332933	0.0225703518439	-0.0103327400859	-0.0290874720791	0.0136443443699 [...]
+449.M21Fcsp	-0.154504530619	-0.41595238138	-0.217275997198	-0.0525476712579	-0.0578031064134	-0.0336048385545	0.0410148286157	0.00494211399124	0.0672563938581	-0.0460957250707	-0.0372843895377	0.0681745149832	0.0205657200063	0.0260116080157	-0.100273366076	-0.0652151642882	0.0240190426349	-0.0167626688462	-0.0540725555982	-0.0201275373352	0.0572794512694	0.0747901404536	-0.0809979626528	0.0144524624426	0.0220134084174	-0.113197257851	-0.0255170577374	0.0306116164222	-0.0371852343652	-0.0 [...]
+449.F32Fcsw	-0.0723270770104	-0.385206888765	-0.325702830426	-0.038956962193	-0.0556350823492	0.165528276496	0.0596267463928	-0.0185031117604	-0.0952999595405	0.065512973828	0.0183163144241	-0.0122904054085	0.0161704529754	-0.0108273874133	0.0106774076072	0.00947348289131	0.00765180863053	0.0315149613229	0.0752544929278	0.0303787658238	-0.0393294840806	-0.00499411537349	0.197542370979	0.0355990201039	-0.129558774356	-0.0157509965226	-0.0841844414622	0.0183575124386	0.000458274739324	0.06 [...]
+449.M41Fcsw	-0.080528695103	-0.350415848492	-0.277049609313	-0.0761695869831	-0.00471274631444	0.0168846879998	-0.0465808808103	-0.0297670424581	-0.00976470360624	0.0148489016494	0.038426058837	-0.0652632067547	-0.0853107437535	-0.0240671745189	-0.00441602062092	0.0616235104546	-0.111929169155	0.0190322449712	-0.0519534029474	-0.0280107012388	0.0794491267045	-0.103628515762	-0.0814153301832	-0.21430208884	-0.0334353114202	0.083705625259	0.0238222523226	-0.0298842192666	0.0918471968022	-0 [...]
+449.M22Fcsw	-0.140462327551	-0.390362507238	-0.240568154668	-0.0661838884321	-0.0662817519496	-0.084778042469	0.0398155288774	-0.000328349870091	0.0780359627662	-0.0667558440114	-0.0149850627065	0.0746888292131	0.00665957215669	0.0185552895222	-0.109579180839	-0.0571553810263	-0.00985716157483	-0.0146402910286	-0.0763656740634	-0.0418265406927	0.0477114421286	0.0665719893875	-0.129985393679	-0.0178158732545	0.0370540573443	-0.0531462517068	-0.015201430847	0.0435226408017	-0.0180780074677 [...]
+449.M42Fcsw	-0.109415000232	-0.369269539114	-0.252430094803	-0.0487541928324	0.000298320646725	0.0620370114758	0.00395748910362	0.0108073783291	-0.0216151041004	0.0374933742653	0.0195907442418	-0.0681350680937	-0.0713493906401	0.0280464535995	0.0164937874796	0.0767495377729	-0.0968325813641	-0.0234642662134	-0.0826793938789	-0.0995931564753	0.10778382905	-0.141937710925	-0.0325312870004	-0.193987311831	-0.000153319831886	0.0688355775914	0.0388372193779	0.015516386098	0.104932910289	-0.07 [...]
+449.M34Tong	-0.175512934004	-0.21093378469	0.356990482521	0.0451577352783	-0.0214744759055	0.0542152873307	-0.0415795629548	-0.0170353312218	0.0206851405179	-0.0372301370968	-4.94659416447e-06	0.0002019794596	-0.000534069175595	-0.0365217602736	-0.0116933567425	-0.058544759801	0.00632931598747	-0.0423130714426	0.0359812110357	-0.0370108286593	-0.0294698067235	-0.044379817995	-0.0380357656809	0.0516305113322	-0.0141589943628	0.0491169141422	0.0112314993543	0.00367678090687	-0.039890554421 [...]
+449.M44Urin	0.191283664973	-0.0844013781301	-0.0160511362043	0.189289927347	0.11566009142	-0.0411120636234	0.100813732999	-0.245279825944	-0.0576380320238	-0.107684643701	0.0117234998979	0.118907912646	0.0862003499498	0.0227678162695	0.0306712942358	-0.035204439559	0.161009311826	0.0396758957618	-0.0168717198358	-0.0442104008578	-0.189799063619	0.0663189935966	-0.0394131443014	-0.17529167647	-0.0109577397467	-0.0207333283419	-0.044307318687	0.0133178242347	0.028172353518	-0.0581747004497 [...]
+449.M53Tong	-0.185447291517	-0.18831823125	0.359249076454	0.0682969786573	-0.0201736427353	0.0907067552879	-0.082088153806	-0.0101121193732	-0.0590384534769	0.00103001778205	0.0472756366491	-0.027845381485	0.0193727090301	-0.000580539855431	-0.0716303658007	-0.093258500411	0.0345181620148	-0.0575908647276	0.0106167343176	0.00691667788086	-0.024993404969	-0.018480662198	-0.0229849985446	0.0323767769422	0.00295685232027	0.0484589589452	0.00808571296527	-0.0436132448903	0.0194391109763	0.03 [...]
+449.M43Frhd	-0.0778733575687	0.0767471280965	0.0966083533763	-0.121531986755	0.0116742498142	-0.0795145679808	-0.00669310596615	-0.0086370730695	0.00545975715337	-0.019143587576	-0.0651229758851	-0.0313055330406	0.0718504632668	0.00102872246263	0.0822182202044	0.0580976231559	-0.0163750817401	-0.00663320179431	-0.024905941977	-0.0694637548456	-0.0416706475787	-0.024982514672	-0.0190733599546	0.00610319477145	-0.0029013867363	-0.00514951873034	0.0298423390901	0.020726419423	-0.07235632729 [...]
+449.M54Tong	-0.189582374406	-0.157652970851	0.358642426587	0.0571330154446	-0.0211210292337	0.0720784706799	-0.0804268574085	-0.0136344349611	-0.0922126530137	-0.00163374752536	0.0517064596567	-0.0153744954376	0.0119927005115	0.0199079191742	-0.0904930694743	-0.091681103251	0.0450083557756	-0.0539805744695	-0.0102815846605	0.022300618373	0.0172657589326	-0.0224660368449	-0.0282669073378	0.0109527831908	-0.00790724514502	0.0403562396969	0.0171567688004	-0.0176023811048	0.0407607373364	0.0 [...]
+449.F23Tong	-0.178089107995	-0.199298570636	0.384517646341	0.0722902839931	-0.0130303457877	0.0920680528098	-0.0537876107361	-0.0154220880476	-0.00478457004969	-0.0138199130127	0.0317612850706	0.00861742529645	0.0182806564603	-0.0121534759311	-0.0587121961657	-0.0623222107413	0.0286801327008	-0.0727180207489	-0.0270228492075	0.00377922772253	-0.0108791078104	-0.00756479199319	-0.0276649444968	0.0349560983907	-0.0371964728922	0.0595124469832	-0.00400837910287	-0.0171990814736	0.0145604145 [...]
+449.M53Uric	-0.113775736855	0.0754300153244	0.0780522475809	-0.0599184526992	0.0692788702612	-0.00131779804765	-0.011353474329	0.0371141265329	-0.0611939418448	-0.0788987378946	0.0305916190097	-0.088691298266	0.0962346149908	-0.05004491676	-0.0811130158487	-0.0528575500458	0.0291764301529	-0.0448482849247	-0.0136204739384	-0.0317354970785	0.0308814203295	-0.0829757604479	-0.0123037792431	0.0707372365546	0.0425718456616	0.0737238859565	-0.0891350573679	0.0567065050496	-0.0287066487284	0.0 [...]
+449.M54Uric	-0.181925210596	0.00537173677046	0.133993721679	-0.0473387125996	0.0664746943893	-0.0493805937801	-0.0381604263955	0.0092163675288	-0.0858220514924	-0.0299277640611	0.0494663475994	-0.0963171203178	0.117179300138	-0.110252445284	-0.020337265407	-0.054496228309	0.0689197963287	-0.0628572247209	0.0545194956175	0.00997119007643	0.0680945220647	-0.0520845828985	-0.0317364289603	0.0232883169625	0.0239843317611	0.0226688595951	-0.0111188189974	0.0380978927008	0.0153567113867	0.0215 [...]
+449.M23Ewax	0.228984201268	0.0587871300783	0.0264057674623	-0.0841539183896	-0.168274221506	-0.0207533788951	0.00256918077454	-0.12546510217	0.00513165295573	-0.0805765021733	-0.116172104649	0.0513742883173	-0.0269883626487	-0.0301339471204	-0.00249461033143	0.0198615623762	-0.0472686887523	0.0520178940072	0.0967411580979	-0.00584754414635	-0.0270237310688	-0.0179520318695	0.00790954241557	-0.0381849725035	0.0511754569967	0.0129041117516	0.0782576287083	0.0308844444501	0.0210062969249	-0 [...]
+449.F23Knee	-0.171098861586	0.0996452915818	-0.0847750497061	0.0488928323372	0.118793083444	-0.0508437638603	-0.103301501056	0.0304955068822	0.0169938272938	-0.015650783829	-0.0510340034046	-0.0509652808522	0.0526316064358	-0.0794204355882	0.070434637859	-0.0644236889995	-0.0117584873534	0.0239104169312	0.0174628087609	-0.0518540955075	-0.0309581165284	-0.0151594486145	-0.0404153586211	0.00807588134805	0.0239728718213	-0.0511181344501	-0.0254320634714	-0.00795095580698	0.011661633114	-0. [...]
+449.F34Fotr	-0.191817837226	0.176562714432	-0.122524073858	0.219609925038	0.0367259262541	0.023922316272	-0.0633789128247	0.0176009182621	0.041390067948	0.0884020670913	-0.102920222505	0.0394315646336	0.00653176954775	-0.0498180730409	-0.0529526120411	0.0670563050302	0.0318994314871	-0.0458741182824	-0.0493926443614	0.0292790832188	0.00452890862207	0.0434724694904	0.0464043348127	-0.015750523128	-0.0168565817265	0.00582245877714	-0.0139272618456	-0.0142757687786	0.0364243103921	-0.018662 [...]
+449.M64Fotl	-0.146960358061	0.123319042351	-0.193110554729	0.199437909898	0.0376000294959	0.0473783771795	-0.0395144780777	-0.00304187228172	0.0624508686359	0.074563760941	-0.0363414951075	0.00195876577012	-0.0209075900655	-0.0447177291891	-0.031347290533	0.00258793109759	0.030851477053	0.0155547799827	0.0127115006908	0.0712844480469	0.00096037014516	0.0342423134723	-0.00965432943211	-0.0398067322756	-0.0132986123939	0.0385473985219	0.00206137041015	-0.0732804006895	-0.00184210820922	-0. [...]
+449.M14Tong	-0.164321710532	-0.162553898398	0.350397595584	0.0434091661327	-0.00905261454535	0.0857556366821	-0.0802927489933	0.00234447255762	-0.0618399845651	0.00203270626657	0.0430529661959	-0.00553052504867	0.00888540929004	0.00214815369489	-0.0670303702326	-0.0913507695343	0.0196300634215	-0.0606514418165	0.00742669882303	0.00120676928551	-0.00949078687442	-0.00771240818841	-0.0272775660647	0.0489384984389	0.0180381948428	0.0577581295818	-0.0157274896191	-0.0265540969121	0.040571373 [...]
+449.M44Knee	-0.205641586975	0.115012814615	-0.165217176256	0.0766447209946	0.0153916918797	-0.0580481545614	-0.0799511197843	0.0358094951601	0.0305059361728	0.0176833824289	-0.0479966788937	-0.0431842971605	0.0317760154431	0.00649548169885	-0.00621044343314	0.0378248195748	-0.029546490474	0.0146289947591	0.0358509387567	-0.0343282297627	-0.0135068395014	-0.031350909195	-0.00421199547877	-0.0457721258236	-0.00958107874136	0.05431702368	0.0310934858236	-0.0149464983626	-0.0440672913231	0.0 [...]
+449.F24Frhd	0.175688150807	-0.113233814047	0.126460802442	-0.0192234968597	-0.00467692941365	0.054505388092	-0.00296888768184	0.167348367575	0.0693868762333	-0.111341267423	-0.0674520869179	0.132385595279	0.0273759816367	0.0892811816813	-0.0397842464287	-0.107671006267	-0.00584411459346	-0.00867935063738	-0.00976447400071	0.0595811001366	-0.0936673653385	0.023322195737	-0.0477868836313	-0.0408015804043	-0.0663042613555	-0.0192857046742	0.0789713889826	-0.0110672710172	-0.0190415928803	-0 [...]
+449.M44Uric	-0.0802680683083	-0.0580660504047	0.21134132811	0.00743199447683	0.0981611609187	-0.00894723244925	0.0545970165251	-0.011458987367	0.0727507778471	-0.110844911356	-0.00667564014361	-0.0518651015524	0.0916739702588	-0.0737194996982	0.0744388996997	0.0286009918284	0.147771973916	-0.0679384299745	-0.0444747570345	-0.0812542668849	-0.0427602665792	0.0415495050199	0.00958603991386	-0.0644858038244	-0.0157993159435	-0.0414470481974	0.0521729021158	0.0255538456055	0.0542473979242	0. [...]
+449.F23Nost	-0.0706072073019	0.107666322374	0.136295369751	-0.123233536005	0.00143091637787	0.00413039189241	-0.0324023596308	0.0558486372252	-0.145228905348	0.0352089213614	-0.0148673607877	0.0306196050353	0.0517574697505	0.00884007211272	0.017480502719	-0.0620575844684	-0.0551027182636	0.0155851981473	-0.0459889947313	-0.0103116103736	-0.0149676204416	0.00524290800051	-0.0362717737053	-0.00978949110979	-0.0335473976955	-0.0721846821053	-0.0359953512662	-0.0349315780925	-0.0040109572367 [...]
+449.M33Nost	-0.0508698087936	0.0841183531111	0.040582938845	-0.121317979441	0.0123976867355	-0.0182054260671	-0.0359640856378	0.0801481359871	-0.0667344196652	0.105357193737	-0.0439531723884	0.113665857762	0.0527817512827	-0.0149177872876	0.0609657967318	-0.0897348989221	-0.0677152250456	-0.041391787531	-0.0374726919808	-0.0203110354194	0.0377508972956	-0.0486210041833	-0.0185821140355	0.0400279236271	0.016404448808	-0.0733072456349	0.0500341077058	0.0326282346445	0.0116901937848	0.02068 [...]
+449.F24Nost	-0.106269227092	0.125289933793	0.0872891455298	-0.0485829955696	-0.000215383694618	0.0261339737873	-0.0279243745632	0.0412627814702	-0.07952393128	0.0449725700777	0.000669880513036	0.0133739298088	0.0518996754051	-0.0164559620647	0.0237729148933	-0.0554201777686	-0.0216617579271	-0.0461635998378	-0.0889269913667	-0.00216527437654	0.0132664787051	0.0238884620241	-0.00731753587208	-0.0280004900974	0.000237119812608	-0.0826710871481	-0.0227832855698	-0.0126585062973	-0.034399042 [...]
+449.M13Plml	-0.0525065935364	0.143968406726	-0.0849838618063	-0.00868105956514	0.0102465399891	0.0772986052513	-0.107108500709	-0.042293524999	-0.0220761812622	-0.108814607007	0.00446239117286	-0.02886602389	0.0348392054534	-0.0173300528578	-0.0270229612461	-0.0113681694892	-0.103707196343	0.00992612965869	0.0638004945978	0.159898146907	-0.0410235273308	0.0185574121354	0.0384109111188	-0.0162464520638	0.0389012517644	-0.00181124371964	-0.041257554417	-0.0205070955826	-0.0601590545914	-0. [...]
+449.F21Indl	-0.152714896715	0.166099106667	-0.0291231010698	0.073932238418	0.0013483432418	-0.00865575594509	0.0626417595321	0.0368709691661	0.0145915470281	-0.0298900151169	-0.0105100034446	-0.00389372976185	-0.0623732856725	0.0454466183721	-0.0137157947623	-0.023205927906	-0.0442951020362	0.053336794202	0.00500498123621	0.00479236307592	-0.0320082873148	0.0259933513749	-0.0522884257803	0.0201119057944	0.0308651192688	0.011195690409	0.0263758665125	0.0152642285774	-0.0546773100845	-0.01 [...]
+449.M23Plml	0.0408714915749	0.156105529334	-0.0618372613529	-0.0780533182285	-0.0437328038769	0.0735542212525	-0.0480542493112	-0.0756572996553	-0.00199633024422	-0.157245349247	0.0133259703798	0.133609383001	0.0478532638553	0.0159047417409	-0.00969934766715	0.0359612590749	-0.0114929163365	0.0126985028768	0.0572182249701	0.0700548193564	0.0429116679948	0.00629894679487	0.0261184131746	-0.00262074061535	-0.00586408943639	0.0956194036868	0.0328609033645	-0.0133016783534	0.00291119169345	0 [...]
+449.M54Fotr	-0.15617290378	0.124053012514	-0.210831684405	0.131534097121	0.0405780308608	0.00226016793902	-0.115559172967	0.00110345761685	0.0328978053968	0.0394471909757	-0.0238662145046	-0.0216948706801	0.0298579904015	-0.0733599291588	-0.0675157155605	0.0343129480458	-0.0162994356892	-0.0694250802899	0.0706513010775	-0.0254178136187	-0.0223806933183	-0.0479011013757	-0.0359899899828	0.0080502921033	-0.0444790477105	0.0531079108741	0.00826643693651	0.0214694564754	-0.0583122129185	0.04 [...]
+449.F21Tong	-0.226795104523	-0.230548166019	0.369937680031	0.0713981939097	-0.023473175799	0.0503560653913	-0.0617765076363	-0.0709585229229	0.0244950452012	-0.0125860894427	-0.00151002135157	-0.0414035645338	-0.0309720416465	-0.0296384622711	-0.0379765953515	-0.0346001198395	0.0169477289397	-0.0514687912527	0.0289502167241	0.00633105842569	0.00257340816468	-0.0286990740676	-0.0159431274672	0.0201557815636	0.0235737959097	0.0162039905554	-0.00934784660915	-0.0191532916488	-0.025946800515 [...]
+449.F21Mout	-0.204833213993	-0.174044247091	0.354959607112	0.0649964254453	-0.0500793394453	0.0136455653761	-0.061101710192	-0.0254740829131	-0.0326397444453	-0.00875539912649	0.0161961675998	-0.0298229551851	-0.00698702945848	0.0206962844642	-0.0248297343889	-0.0199170445928	0.0597318101437	0.025493098669	-0.000672312065558	0.0331757835414	0.033039628254	-0.0185895981286	0.00675673069018	-0.0364090361966	0.0186562276296	-0.00594510251628	0.0406616578092	0.00492963289109	0.00863582120031 [...]
+449.F21Hair	-0.0334124622565	0.158391303776	0.0430414001597	-0.0370969661889	0.0191981521588	0.0630484850773	0.0852201216545	0.0579031846808	-0.0357959181411	-0.128305123165	0.00418004450024	0.0123410766429	0.0752303688214	0.025371543941	-0.0401950624544	-0.0128342196929	0.0287297835692	0.0260898010329	-0.0615309178929	0.0504138838288	0.0358931943967	-0.00947241427523	-0.028615504348	0.0125000717051	-0.0197288686129	-0.0535145580851	0.0284616744738	-0.0470860625629	0.0316550385825	-0.003 [...]
+449.F21Forr	-0.175001225856	0.170267705755	-0.00946304273282	0.0759411747647	-0.00206308802511	0.00149116120942	0.0148701151864	0.0521384600476	-0.0292714558778	0.00489879837331	-0.0112063992818	-0.0180148873717	0.039702615262	0.0550492620264	-0.039243755548	0.00768162376585	0.0454598486837	0.00631174840956	0.00904321310781	-0.0102499479225	-0.0420471153335	-0.00751993196936	0.0169948011471	-0.00566198268097	0.0714293445959	-0.00855727735135	-0.0193787426221	-0.0180521730553	-0.001094627 [...]
+449.M31Mout	-0.218499160144	-0.162684601997	0.292473503718	0.0613427351952	-0.0485827470372	-0.0128845793575	-0.096716205107	-0.0312228852998	-0.0800811238261	0.0284495155048	0.03469027478	-0.0739450047754	-0.0190732721866	0.033746179462	-0.0241397745664	-0.0513485855698	0.0293545573613	0.0891700899443	0.0532644078013	0.0385882677178	0.0395563862238	0.0100457344424	0.0320685630515	-0.0569436251909	0.0565722078192	-0.049747394521	0.050997044191	-0.0148531032688	0.0174480271192	0.065054698 [...]
+449.F21Forl	-0.19938453989	0.169336608625	-0.0362691603906	0.116486187376	0.0402011900098	0.0125617585181	-0.0740580257986	0.0269745251206	-0.0538455276676	0.0675973732878	-0.0579903756649	0.00682627307318	0.0571737519086	-0.00982254834296	-0.0416288420547	-0.0329536016861	0.012692086398	-0.0178303161751	-0.0130938486333	-0.00699301080337	0.0332126910021	0.0285085605697	-0.0243068041955	0.0345947609049	0.00967869536039	0.00122198503151	-0.0431959303169	0.0280645549232	0.0132493902331	-0. [...]
+449.F12Indr	-0.167984755557	0.190486854177	-0.0553219693717	0.122347893113	0.007200626615	0.00959962128879	-0.00435038362984	0.0639022522137	-0.0408268803851	0.00833730426154	-0.0337804239978	0.0191612257738	0.0056552210386	0.0673409709108	-0.0310770519231	0.0447836555681	-0.0327627796616	0.053789754301	-0.028101586969	-0.0050400611343	-0.0233228333475	0.012715451683	0.00978793483739	-0.031428224252	0.0475116321877	0.00444854828894	-0.043116522472	0.0628153418562	-0.0434837848963	-0.0394 [...]
+449.M32Ewxl	0.241459184779	0.025726044518	0.102885134495	-0.052895822564	-0.0992320979714	0.0415954593518	0.0390991582092	0.0671076082534	0.0111010094462	0.0223503833494	0.0997674539074	0.0175954162385	0.00705716123245	-0.0723780217519	-0.0825558299305	0.0494042894078	-0.138100259616	-0.0406565068213	0.0125913088803	-0.0123611812783	-0.0927542109262	-0.0264387809579	0.0556825330825	-0.016774704482	-0.00323192191123	-0.0306583082602	0.0825256746246	0.0660097886593	0.060478769841	-0.035569 [...]
+449.M31Fotr	-0.126722124156	0.198642609853	-0.127137193287	0.0873996225741	0.0437741662124	0.0371735838526	-0.0027975064306	0.0084981903881	0.0217546839086	-0.0143182964631	-0.00151032237852	-0.0138341721857	0.000375276557006	0.00326176246229	0.00103160750302	-0.0807642892722	-0.0148116922948	0.0434824826902	0.0656904397496	-0.00967043394522	-0.00784741104825	-0.0110678685048	-0.048685763576	-0.00408840935213	-0.0881432733095	-0.0498450166405	0.0840224949781	0.0253466692773	-0.0626130753 [...]
+449.M31Tong	-0.187709512169	-0.198826664643	0.393087972258	0.0591944559829	-0.0336876941215	0.0472335164379	-0.0345162058655	-0.0261644096077	0.0218409531415	-0.0195147276227	0.00909154811638	0.00832562426472	0.000229731067266	-0.0122172940218	-0.00847683082741	-0.0166009973882	0.0182546180216	-0.0386895991494	-0.0112255209808	-0.00183833272264	0.0143409613341	-0.012790800969	-0.0131849330924	0.0160513670309	-0.0103553138138	0.0100327908305	-0.00585425016634	0.0121879046468	0.00262080231 [...]
+449.M32Tong	-0.1330872129	-0.134438378729	0.355048543302	0.00498511748383	-0.0689418461461	0.0805334358893	0.0106092818008	-0.0190219493802	0.0189864862521	0.0481940256326	0.0347327236997	-0.00774206784781	0.0471820084277	-0.00938349192474	-0.0348705544465	-0.0169330476602	-0.0520932827807	-0.0125263184134	0.001832872054	0.0382920949371	-0.0694640242052	0.00458698823304	-0.000693236662311	0.0191821001493	0.00587364826163	0.0175961482856	-0.0339213890213	-0.065105545595	0.0267725018754	0. [...]
+449.F22Forl	-0.131516233037	0.214063001389	-0.0918396936275	0.0598876168879	0.0622777698398	0.0069777507625	-0.00407013627598	0.0519496073577	-0.0370932937165	-0.0228092168241	-0.0388709772704	0.0314144532734	0.0500842524551	0.0257888428389	-0.00362943404091	0.0412769994346	0.055479693185	0.0343545023286	0.0285018567383	0.0202445525955	0.0201387374752	-0.026740702557	-0.0410240048261	0.00312169629	0.00826681736	-0.0116114344924	-0.00939894775615	0.0181872439523	0.0110884102843	0.00112065 [...]
+449.M32Nose	0.37110237527	0.0727465789931	0.000467981760511	-0.0593256661322	-0.134570525925	-0.00605601763561	0.0510034469426	-0.0325551483001	-0.0878300929157	0.0442281583193	-0.0452807009215	-0.108627543224	-0.0379704988423	-0.0656263366013	-0.102465319852	0.0663770494864	0.00437773389544	-0.0243603304486	-0.0426636286062	0.0296827330341	0.00272087230596	0.0355910543904	-0.0150454500865	0.0301363348149	-0.0418472194204	-0.00098933304047	0.0505009323451	0.0547671458532	-0.0080888442122 [...]
+449.M32Plmr	-0.0921013141194	0.19743404343	-0.0610856462294	0.0132153973052	0.0144721864084	0.013031746813	0.0423723990152	0.0307827270019	-0.063131780489	-0.0315013045179	-0.0015254102708	0.0574879038744	-0.0630107093944	0.0518220916699	0.0122199029038	-0.0409993713871	-0.00768906649351	0.0841057696804	0.0787913708542	0.0386323782234	0.000201767106395	0.00101915508493	-0.111509841827	0.0385456813701	-0.0919542796873	-0.0426611616407	-0.0241302416774	0.00731485522583	0.0411315716887	0.00 [...]
+449.M31Hair	0.0939128428507	0.0892903597829	0.0827407622102	-0.129712309833	0.0194590523308	0.00094587610757	0.013333649964	-0.000388243328355	-0.040761294045	0.0942771217487	0.102935589556	-0.0432517783971	-0.0809147224595	-0.0626495363779	0.0810960381521	-0.0234347524731	-0.10449553771	-0.0644999558337	-0.0726978899535	-0.00995036129556	-0.101125910993	0.0129694922495	0.0161339088004	0.0445208895305	-0.0959874716099	-0.0153881811013	0.0438045971878	0.0167564177143	-0.0206595234389	-0.0 [...]
+449.F12Aptl	-0.107045941238	0.170027675022	-0.0857846680453	0.0525274111819	0.0315901307187	0.0351520889743	0.0046165025282	0.036577854161	0.0110373224795	-0.0116503521659	0.116347993715	-0.0332744588251	-0.0177593502292	-0.0501913977558	-0.0299293637132	-0.0642501499886	-0.0196326012993	-0.0548806103759	0.0347593659367	-0.034343713551	-0.0524403663408	-0.0497378605869	-0.0489726317823	0.0530290701423	0.00874266022035	-0.0259675385781	-0.00312344784607	0.0610578885175	-0.0335408696934	-0 [...]
+449.F22Indl	-0.158697112685	0.184672430118	0.0331075514463	0.0638268603259	0.0148495919866	0.0349443304128	-0.00460304532148	0.0430023368967	-0.052510001937	-0.0474519913876	0.00464039731932	-0.0134203134842	0.0340160736985	0.0479195527315	-0.0844031971276	0.0073419461414	0.0375939116303	-0.0437686388622	0.0193620583506	0.00729734831098	-0.0381356468732	0.00602337536952	-0.0469680953295	0.0335750887685	0.0187909605545	0.0581275406736	-0.0431123914698	0.0373206524591	0.00815822985031	-0.0 [...]
+449.F21Nstl	-0.031275859196	0.0730934681471	0.142618996122	-0.123989483608	0.00157855014837	0.0105496814925	-0.0183316829891	0.0755238136826	-0.0718744059585	0.0991808513726	-0.0231745883504	0.061083064066	0.0284416375304	-0.00346830812085	0.0386058740942	-0.0577165426839	-0.0928199909771	-0.0453579181481	-0.0448832796031	0.00590427764229	0.00608317696824	0.0109718704813	0.025253952073	-0.0102984396895	0.0183613590817	-0.0656836394798	-0.063228042525	-0.0192134828188	0.0733447838561	-0.0 [...]
+449.F21Plmr	-0.127414335134	0.192272933834	0.0057028817355	0.0329518870702	0.024661963566	0.0230770805032	0.0155447692389	0.0433527833202	-0.0594323391495	-0.00843348091718	-0.0246645275475	0.0547177317029	0.0373765926171	0.0730515921737	-0.0296366958545	-0.0147676262946	-0.0247126151925	0.0205114645292	-0.0268200724857	-0.00798037636823	-0.0677685287845	0.0211283455634	-0.0483142154812	-0.0170195975051	0.0587138984075	0.057351938739	-0.047420631041	0.000664734068391	0.00607584319935	-0. [...]
+449.M32Pinl	-0.0246133701832	0.118452895895	0.0202631428013	-0.0559017723964	-0.016901169929	0.0144419895611	0.0494474237388	0.0518556896879	0.00283738083507	0.0461850502909	-0.000559948583629	-0.0555737211936	-0.0868494143324	0.0343827295777	0.0295348283405	-0.0757277517211	-0.0580085911078	0.0623252537508	0.0123842462628	0.0900531464774	0.04241383836	0.0416954160858	-0.0916422225425	-0.0318245526369	-0.0678320389552	-0.0703926996241	0.0628046784523	-0.0897107609582	-0.0199738792709	0.0 [...]
+449.F22Tong	-0.204196721427	-0.203162761778	0.37054087256	0.0605962607272	-0.0440678505117	0.0419068177413	-0.0687853027012	-0.0468082271411	0.027440293019	-0.0173458398985	0.0136074621229	-0.0427253067355	-0.022070543145	-0.0293634884729	-0.0391702896563	-0.0498099843272	0.0225728041676	-0.0449129211542	0.0407876265631	-0.00584585789348	-0.0077345481921	-0.00984983880962	-0.0226760500712	0.0298689317071	0.0235550652753	0.0272117612973	0.0157579808768	-0.0511935210056	-0.0021990150669	0. [...]
+449.M32Hair	0.0953115650933	0.177458918339	-0.00434083736699	-0.0519648844529	-0.055568756031	0.0594385135939	0.0743433178775	-0.0390890297728	-0.0175653380641	0.0850031214063	0.104336404741	-0.0859711832144	-0.145002887139	-0.0159736760548	0.0258226421874	-0.0195780227668	-0.0652089013096	-0.00470594838865	-0.0707981516046	-0.00398352008972	-0.0421762102927	0.0114687480726	-0.0239340673338	0.00893713463102	-0.020550465394	-0.019665421601	-0.0186643541371	-0.0552043410985	-0.018336335702 [...]
+449.F12Mout	-0.16530259832	-0.132505821227	0.347912528565	0.0147805972913	-0.0753184759649	0.0171596479841	0.0698962797264	-0.0481620032736	0.0392569686181	0.0488514800774	-0.022451786068	0.0233025817051	0.0152125124924	0.00992468632519	0.0423426160198	0.0874691416665	-0.0221635580842	0.0601103220844	-0.013921936497	0.0330986707166	0.0593080490213	0.00317274719711	0.042370664995	-0.0180196122591	-0.023035834558	-0.0254355325886	-0.032930158534	0.0379795742767	-0.0169488595132	-0.03069753 [...]
+449.F21Aptr	0.148733286965	0.141103517702	-0.0409039672166	-0.165525436511	0.000336240623249	0.0359875896302	-0.0310826511054	-0.053937733376	0.0216709664489	-0.0676228330923	-0.00301210071442	-0.0280032110094	0.0140732034731	0.0574157427401	0.00287628263414	0.066802706779	0.0262228110599	-0.0583786568915	0.0250369689944	0.0826174991691	-0.0506941757426	-0.0392345449617	0.00976266487139	-0.0210144613967	-0.0131235927482	-0.0856947497214	-0.0826889326338	-0.0228974836407	0.0195594081567	- [...]
+449.F22Plml	-0.11249376453	0.214520063547	-0.0340936092314	0.0506025473964	0.0340687963785	0.0455560926812	0.0379430754853	0.0364149391938	-0.0166364901634	-0.0887471050889	-0.0374479168535	0.00302335848704	0.0412840875572	0.0674635935085	-0.016041678031	0.0347809040825	0.0148424992158	0.00961855791468	-0.0480299668354	0.0101787985998	-0.00814478761796	0.0147816737584	-0.0238181997387	0.0176138512288	0.0255862156426	0.0452502960849	-0.0642423049968	-0.0177165891436	0.000962992907791	0.00 [...]
+449.F22Hair	-0.139373204946	0.157234090429	0.0680160017215	0.0281068843937	-0.0242573155722	0.0536140749353	0.123343323156	0.0574129981971	-0.0152920132756	-0.0333121302593	0.0525054829629	0.0223873434615	0.00838566144921	0.0108071171563	0.104986165654	-0.0172364617984	-0.0150647515661	-0.028675387401	-0.040793586853	-0.044347050927	0.0339954483524	0.0304112353177	-0.0179090947499	0.0362999647419	-0.0689934356083	0.0223813626275	-0.000287682672699	0.0259727752909	0.0272238317085	-0.01069 [...]
+449.M41Urin	-0.127893299285	-0.0432095484942	0.223942501274	0.0185105094895	0.0290924381238	0.0261202258805	0.0288465686257	0.0390656840756	-0.0712078826022	-0.085444862798	0.0587805848944	-0.0769774793317	0.0150006664613	0.0483276331988	-0.0801646381027	-0.0316856144042	0.0753718007097	-0.0189933362451	-0.00326471764811	0.0309414529239	-0.0538608964626	0.0172511860333	0.0183957910973	-0.142818685388	0.0579432881901	-0.0498396465404	0.0239480270003	0.00629881050452	0.08601182025	0.069689 [...]
+449.M41Tong	-0.157892847199	-0.193725956763	0.368216157731	0.0380060026075	-0.0391739367372	0.0114267874058	-0.0199662198704	-0.0372111707298	0.0561629736893	-0.0168745617229	-0.0430429811169	-0.00737052052776	-0.0381257935606	0.00558011224491	0.018389209205	0.0385902525214	0.0481003247032	0.015163748616	-0.0370059188612	-0.000919650180462	0.0105293672828	-0.00750253248626	0.0428714048719	-0.0234477989818	-0.000292135678466	-0.016596547164	0.045396135247	-0.00744042508889	0.0022947548626 [...]
+449.M42Indr	-0.159418562135	0.125055351159	0.0646162587084	0.028382002026	-0.0290718594958	0.00335892840305	-0.0157523164776	0.0268027966261	-0.0978747037759	0.0238231294108	0.000347128753431	-0.014670038757	0.0502774176352	0.0771760250353	0.00179629102987	0.0459086299296	0.0386234995513	-0.0016567959286	-0.0246615215806	-0.041318611438	0.070483438289	0.0340556353923	-0.00828286857055	0.0512935606424	0.0118149546972	-0.00705624352681	0.0499163071248	0.0410228626518	0.0210741954871	0.0620 [...]
+449.M42Tong	-0.157174706727	-0.205206639246	0.390956549693	0.0370612754395	-0.024424510403	0.0334567290667	-0.00668918684231	-0.0187231272383	0.0672120429676	-0.0318806762797	-0.0317100466144	0.0286009339327	-0.0102774779507	-0.0122517080649	0.0208099600053	0.0240391841077	0.0130623142699	-0.020379458614	-0.0450434390178	-0.012036169738	-0.031943608896	0.00539146915096	0.0198420513865	-0.00891626833124	-0.0190080461386	-0.023114553156	0.0305098441173	-0.00477469059525	-0.00639753867229	- [...]
+449.M41Nose	0.167336331298	0.0446778206747	0.0980289885289	-0.169360584807	0.0713319702892	-0.0372899680401	0.0537005752777	0.0944460265988	-0.04142724812	0.0656511642793	-0.0508936446134	0.0183505859514	-0.00487237376579	0.0239940057036	-0.0643877047064	0.0831297520169	-0.0161346509415	0.0550286511113	-0.101728064609	0.0243718363188	-0.0598378049578	0.0025407995903	0.00391593717796	0.0054224456012	-0.028037842308	0.0103138821584	0.0183088427829	-0.0633672352216	-0.0418335668997	-0.00866 [...]
+449.M42Urin	0.115552076322	0.037432293574	0.0350326660918	-0.141543183838	0.214019882071	-0.0104152608128	0.125607271997	0.0845045269487	0.00531239309332	0.00660116065032	-0.0359859610257	-0.136055237933	0.0518931065548	-0.0367815777431	-0.122424581498	0.0294860967237	0.092440823582	0.0376863264492	-0.0134023768537	-0.0118670666947	0.0508083325647	-0.0405258847087	0.00834587617393	0.0107379453072	0.015791677737	-0.0465044824842	-0.0396405261287	-0.00819088319531	-0.0368304108198	0.022937 [...]
+449.M42Plmr	-0.169887498025	0.192970052725	-0.0501815434804	0.0917686064363	0.0261187051258	0.00459685806262	-0.0132369290781	0.0613541386343	-0.0922665296019	-0.0013667741303	-0.0233644905992	-0.0021343075973	-0.00194976370886	0.0805839888582	-0.0394403138435	0.0806344661394	-0.0205815446619	0.0678740141892	-0.0147365010041	-0.0404769044599	0.0119288258672	0.0254716709265	-0.0263564857464	-0.0125512119958	0.0010336889192	0.0381741270082	-0.0248223845563	0.0296574157069	-0.0378442690729	 [...]
+449.M22Nose	-0.180954357019	-0.0705122052842	-0.140515042958	-0.132439548942	-0.0988669384097	-0.253815261926	0.0135510098977	-0.00898624824613	0.0408304796075	-0.0530211953466	0.035575628517	0.0309114890229	0.0364646314923	-0.00772590963207	-0.0659164628901	0.00378498751382	0.0262294496505	-0.0354275399383	-0.0194539812744	-0.0315768322977	-0.0476594813246	-0.0194454010975	0.022085540948	0.000120311739554	0.0199472742085	0.0126660333472	-0.0137222826968	-4.12972325086e-05	0.025485086811 [...]
+449.M22Nstr	-0.175657255001	-0.0891064899375	-0.162921016087	-0.134035701091	-0.10532950441	-0.251391663544	0.0155155557007	-0.0219240788148	0.0187844288403	-0.0646404896001	0.039067814892	0.0481458707246	0.0251288249053	-0.00941667025318	-0.0672404470076	0.0110347488659	0.013134011097	-0.0209055963809	-0.014820918097	-0.018610518623	-0.0112867929958	0.0258758578411	0.0290628202015	0.0199417014023	0.00858000926737	0.0206033594492	-0.0189724136406	-0.0245304364379	0.0152611854291	-0.00811 [...]
+449.M21Ewxr	0.0136406565862	-0.108971869605	-0.0357925834974	-0.132943004794	-0.0839162355978	-0.119859982234	0.107254501721	0.115949463652	0.159175671296	-0.0623322560296	-0.0282671836687	-0.0686224436077	0.0896270590097	0.0199598428495	-0.00243060798427	0.0896737246633	0.0251553728981	-0.0641064127638	0.050120098729	0.11301835801	0.0200386504366	-0.0298778279335	-0.0193810327315	-0.0251068724977	0.00196369371914	-0.0395255307454	0.0201540078845	-0.0540183123853	0.0507339341082	3.037777 [...]
+449.M41Plml	-0.165057488321	0.148072194439	0.0589406149951	0.01758465021	-0.00256518240271	-0.0290138902716	0.0170129843671	0.0323233355336	-0.0808558094533	0.103382312997	0.0175665405055	-0.00909702702505	-0.0270064279856	0.0369943679312	0.0706423764423	-0.0251862664147	0.0334494519052	0.0365044865923	-0.0162331355486	-0.0422823488533	0.0270694444247	0.0207465292568	0.0320042342597	-0.040367233682	0.00279950366421	0.0065283238158	0.0424767965503	-0.00333869684859	-0.0251695565154	0.0022 [...]
+449.M42Hair	-0.0597034991385	0.18399634314	0.00567828483964	-0.0227036870205	-0.0123641801267	0.00976204182563	0.136491453684	0.0367994790061	-0.0704422726571	-0.00840832744192	0.0339501374527	-0.0270849465497	-0.0602622314638	0.0475053718015	-0.00326382461811	-0.0237059096695	-0.00365911798944	0.014646585474	0.0240861640702	-0.0400824095458	0.0124885314472	0.113134709882	-0.00786915751361	-0.0436929115389	-0.0368398126019	-0.0497798303063	0.0612163566036	-0.0457274504963	-0.004085330480 [...]
+449.M21Pinl	-0.0966157181682	-0.0944911319697	-0.0797355697943	-0.142734618416	-0.0332406862581	-0.182156223765	-0.000967396704925	-0.00520807911212	0.0409660850248	0.0468000032897	-0.0342488483154	-0.0100540602764	0.0540240505114	-0.0226488070501	0.0191653598061	0.0592496363775	0.0356089319398	-0.0364312039016	-0.0162519061951	0.0830926629506	0.00630253323725	0.0682671972898	0.0276091305897	-0.0445552329682	-0.020836674552	0.0179267004659	0.0459537222873	-0.0761798471574	0.056478840997	 [...]
+449.M21Knel	-0.209365883637	0.0874039293133	-0.175573613875	0.0540376523238	-0.035027645872	-0.151965311024	0.00159349474708	-0.00834599778002	0.0983932940882	0.0255391576796	-0.00140264220351	-0.00407703250266	-0.0381144442494	-0.0189972911606	-0.0302884406636	0.0047815869393	0.0711798636442	-0.0342519496743	0.00229027559197	0.0226477549885	-0.011467201696	0.0120002484993	0.0118300282879	0.0364260245441	0.00631461161942	-0.00912056550437	0.0470020585521	-0.0494103496858	0.00595319643796 [...]
+449.M21Frhd	-0.182932428029	-0.0584905006433	-0.02866745304	-0.136978051286	-0.108253612198	-0.243352584871	-0.0457033609093	-0.0593266340438	0.0252724506813	-0.0345158135447	0.00199966289435	0.0103306515775	0.046716182811	-0.018463063333	0.0156961162236	0.0364754668251	0.0049991135266	-0.0072745286113	-0.0217331857925	0.029089092611	-0.0125427776696	0.0185395512758	0.0833453202539	-0.0317834702887	-0.00351613961585	-0.0286757546733	0.0208607683719	-0.0531330888394	0.0235600657918	-0.018 [...]
+449.F31Ewxr	-0.0179945837717	0.0141328372471	-0.0893261353077	-0.0648235290682	0.0300328826171	0.0868128429309	0.0629007003803	0.104712628061	0.0106449801947	-0.182118810804	-0.0263449446735	0.0296762245218	0.0235591460105	0.0312668700562	0.0681300450948	-0.00741874715024	0.0460347524898	-0.0674439331988	-0.0352640789629	0.0387008158472	0.0752228179417	-0.0390344261855	0.0145212132073	-0.0405220569537	0.0328126881583	-0.0115811435404	0.0648868663193	0.00681562868677	0.0282951892594	0.033 [...]
+449.M42Nose	-0.038745892065	0.090446694538	0.157435809449	-0.134018036234	-0.0296257604229	-0.015898380933	0.0736700445761	0.0992495251744	-0.126803671165	0.00987743614597	0.0320654203818	0.0100592544064	-0.0105506729719	0.0890198354838	-0.0677757911779	0.0565007340892	-0.0572860659346	0.00436677564822	0.0217903731382	-0.0258754453107	-0.0409828257048	0.027921090278	-0.031226222504	-0.042506134449	-0.00270695726006	0.00170522991716	-0.020324222936	-0.00924370631865	-0.0142321182458	0.033 [...]
+449.M42Pinl	-0.0472596750547	0.0724345665628	0.165641932631	-0.0926692267189	-0.0631257375232	-0.020955511745	0.0294854898837	0.0970662247986	-0.141180531938	0.0410418712375	0.0260063429772	0.00926611562465	0.0117806606394	0.0881278919875	-0.0661497610007	0.0493088835537	0.00263751348954	0.0190224169122	0.0115414555201	-0.0423135804641	-0.0184436006861	-0.0292851906205	-0.0201983098091	-0.0149755791732	0.0129214506336	0.0583221300334	-0.0301470395471	-0.0132769277234	-0.041048613247	0.06 [...]
+449.M41Navl	0.176051852262	0.0206777120479	0.0587775251411	-0.14067744708	0.137773151916	-0.0114248563994	-0.0352519805137	0.0817883315408	0.0307130528878	-0.0403026729447	-0.0908904251222	0.0217305743459	0.00956638372846	0.138113802959	-0.0339321811648	-0.090113064062	0.0821530229214	-0.00567735182215	0.00990435944615	-0.0622135324141	-0.0226075879646	-0.0068826295254	0.00259341625021	-0.00133683827023	-0.0174576375196	0.00775994344429	0.0333759689197	0.00775121140972	0.0319641525181	-0 [...]
+449.M21Navl	0.220478692812	0.0164411570694	0.0965204906625	-0.129461060465	0.0141835202638	0.0300796771163	-0.0362965679072	0.0138116828065	0.0911656169462	-0.00365955274432	0.0343544461052	-0.0126266652604	-0.0215082232667	0.0930879991458	-0.0610521852402	0.0777218950771	-0.0202132617201	0.00460307334974	-0.00385501473247	0.130671605854	-0.00947486885958	-0.0353769851575	0.0278054102428	0.0321641156329	-0.0509079800923	-0.043452065817	-0.0103703377762	0.0314572288793	0.0503452382964	-0. [...]
+449.M41Mout	-0.223920869027	-0.181672208335	0.330380159406	0.0747472810286	-0.0491003222113	0.00130664841701	-0.0580335025804	-0.028391613845	-0.0521477241979	0.0158179239961	0.0113551989321	-0.0251444027264	-0.0060575950265	0.0500580432814	0.00455543753682	-0.000202404758617	0.0490588745835	0.0877374890784	0.0274396354012	0.0136969891502	0.0611213110183	0.0251768415813	0.0466495866818	-0.0536313560214	0.00446395113641	-0.033834147948	0.0620682735871	-0.00157879770888	-0.00351603870866	- [...]
+449.M22Forr	-0.1979966958	0.0553946898848	-0.158753070396	0.00893606971	-0.0502849238869	-0.128974614032	-0.00585350924307	-0.00533166666906	0.0238357249591	-0.0335486909735	-0.0216317244577	0.0264942463134	0.00225131283875	-0.00936521867036	-0.0124548609729	0.0476512881573	0.0471031600472	-0.00509129840022	0.00349516835895	-0.0150861833904	0.0148484005585	-0.0022027690805	0.0408304172919	0.022558311485	0.00543662810752	0.0635460508178	0.00789490919347	-0.0421895710801	-0.0109909173961	0 [...]
+449.F31Indl	-0.130433436093	0.20371527184	-0.06762039563	0.0845355307368	-0.0169904290308	0.00573719326243	0.123566682417	0.0179441786808	-0.0151269918932	-0.045331819621	0.00242826217956	-0.012530827009	-0.0737294096902	0.0482018142077	0.00835379483813	-0.0252999716399	-0.0133428433072	-0.00417565662161	-0.0170437872047	0.0185903748862	0.0351691591918	0.0547443268942	0.0175310582514	0.025888326999	0.0204165510757	0.00258084750718	-0.0439618871765	0.0206704812179	0.0415801186907	0.010920 [...]
+449.M41Forr	-0.169860360082	0.174806666346	-0.0507150870163	0.0736590012783	0.0178414132535	-0.0327016079031	-0.00592167356763	0.045886960745	-0.0226551187223	0.0516828392406	0.0256745599642	-0.0789771094136	-0.0614000003384	0.0687255758594	-0.00983868531323	-0.0182084352038	0.016108700442	0.0410914027388	0.00435452921045	-0.0527598154642	-0.0830865088459	-0.0272145236762	-0.0270416864542	-0.00895147652369	-0.050422500002	-0.00980205671167	0.0157072374688	0.0122898054459	-0.0757362482101 [...]
+449.M22Hair	-0.182942304521	-0.0606330039131	-0.225781552549	-0.0660377652578	-0.0797338980185	-0.20996890157	0.0270363309467	-0.00590526960852	0.0767489583499	-0.0358045167911	0.0241329638309	0.0110570501188	-0.0368555010412	-0.00979045993216	-0.0462812491346	-0.082982083908	-0.0191597886879	0.0239542661249	-0.0277921129024	0.0386664031649	-0.01019818738	0.0493735903596	-0.0604174313149	0.00184203105136	-0.00859690658021	0.00970084821396	-0.0126884525835	-0.0563017956303	0.0013102825820 [...]
+449.M22Ewxl	-0.102123204127	-0.0799732371602	-0.107457181848	-0.159745025587	-0.095728306051	-0.214098151586	0.0499082618785	0.0292477989621	0.0882049738389	-0.00580703283986	-0.0256932167564	0.0826883359335	0.023829620044	0.0450639658329	-0.00119360842598	0.0132572405106	-0.0146861205677	-0.0763954060141	0.00553808912152	-0.010991258397	-0.0374649784435	-0.0142503278734	-0.0202385022958	7.40860835223e-05	0.0513650332531	-0.00248094644238	-0.052281242243	-0.0219286805785	0.0341441414788	 [...]
+449.M41Kner	-0.0944768052137	0.0993753812114	-0.173249106352	-0.0200950387004	0.0541672939724	-0.0148645512023	-0.041826930907	-0.00538837716331	0.0330811992797	0.0404665895103	0.0712030859434	-0.0754683663526	0.000556149410678	0.0242303072329	0.0570654968326	-0.0254288010135	-0.0466875120807	-0.0155689912692	0.0507152557411	-0.0186914449568	-0.0760781847611	-0.0290201077254	-0.0402822362707	-0.0985195156029	-0.0313978568856	0.0498409325784	0.0114872369425	-0.0270506588055	0.026769722471 [...]
+449.M41Pinl	0.0591545413389	0.114236926982	0.0538088047611	-0.100663310946	0.0416936030236	-0.0170677976937	0.0764225073068	0.116936503559	-0.0154274719179	0.0582328233813	-0.0480305602293	-0.0827028351925	0.0163481479825	0.0558352589486	-0.037139958551	0.0588698133209	-0.00528179649461	-0.029490719685	-0.0586188921115	-0.040336308394	-0.0238104127883	0.0563439092068	0.0101752514502	-0.0402262449783	0.0115746361688	0.0912428603256	-0.042767753869	-0.115506398573	-0.0494429258977	0.025904 [...]
+449.F31Plmr	-0.187687656766	0.186665895044	-0.0389826378226	0.0863070915965	0.0149582285277	-0.000618167535351	0.0338316150205	0.0414611656144	-0.0273177259817	-0.00287769201125	0.0287412691669	-0.0316799687974	-0.0541028115933	0.0170619759544	-0.0277927924624	-0.020455120775	0.0326790170623	0.0187375290576	-0.0471024825617	0.0511316862615	0.0267472646328	0.0273443996312	-0.00104548044371	0.0159687010841	0.0103819918206	0.0280740979121	0.00951590379297	-0.0295486271789	-0.0230551890529	0 [...]
+449.M42Forl	-0.163611707835	0.200039096797	-0.047605902198	0.0535191012692	0.012226021765	-0.0354750309326	0.0323218274611	0.0519410102103	-0.0624702596155	0.0480896323307	0.0209505869603	-0.0185149639369	-0.0398585796748	0.105750033865	0.0208057142507	0.0290084530301	0.0104291369804	0.0833386373288	-0.00906482368426	-0.0535715075319	-0.0157633392208	-0.00493987478326	-0.00793510359559	-0.023584731495	-0.0169471100769	-0.00306717006556	-0.00712374026806	0.0110028011807	-0.0198765468462	0 [...]
+449.M21Nstl	-0.204929282034	-0.175876381295	-0.122184842471	-0.117203870225	-0.144359833301	-0.270832592405	-0.0158531711082	-0.0323952627698	0.0275721667767	0.0143984110917	0.0688946295151	0.0128563029356	-0.0238782432728	-0.0182653213903	-0.0157704854958	-0.0346123429967	-0.0290196592714	0.0213977283192	-0.0785728972436	-0.00738515211468	-0.0258073049624	0.0361916648819	0.0565095296632	0.0140865532368	-0.0394411984859	0.00764845521048	0.0172731790761	0.0162942617589	0.000120618915264	- [...]
+449.M41Frhd	0.0604259651998	0.0766458870858	0.0973710149731	-0.156882179304	-0.0108200891645	-0.0582076043629	0.0310377248764	0.0499130010524	0.0429363565277	0.0557488885456	-0.0981450811592	-0.0363698992906	-0.0359006844987	0.118131035299	0.038714289249	0.132773764052	0.0187603023479	-0.0516156824529	-0.0191877291422	-0.0564062773032	-0.045716709743	-0.0365581183069	-0.00940125914581	-0.0200040230377	0.0117984549809	-0.0231770093051	-0.049806591844	0.0364749930408	-0.0480271800214	0.003 [...]
+449.M22Plmr	-0.218957326137	0.0818533489414	-0.145504524108	0.0775165749504	-0.0461507440764	-0.149744422738	-0.0157971414621	0.00641743143482	0.048843186406	0.0506395135456	-0.0202584918391	0.0222972061801	-0.0479165572441	-0.0141126462066	0.0255020607078	0.0509809409123	0.0383952893144	-0.0072326353026	-0.00425194429796	0.0067198683683	0.0238573746018	0.0395875667081	0.0499807530118	0.0179798481424	-0.0206910678253	0.0116429536495	-0.0234169045403	-0.0360951579491	0.0598021856714	-0.00 [...]
+449.F33Plmr	-0.180495935412	0.141276334301	-0.0990353876262	0.218975808905	0.0196921227261	0.0463950591596	-0.011446401037	0.0372424409853	0.0137723323625	0.0782923963229	-0.078901957814	0.0752387518098	-0.00912086952762	-0.0417097622179	-0.0995148892	0.0767873754159	0.0484769613399	-0.0524417025107	-0.0237020702892	0.015554920806	0.0480854172526	0.026190195567	0.000101047075255	-0.00811548390393	-0.00529361025173	0.0321748810599	-0.0648144751979	-0.0194941282957	0.10894323579	0.01886782 [...]
+449.M23Fotr	-0.0300230212225	0.162516656994	-0.129093091721	0.163434387687	-0.0262866818845	0.136694718757	0.00149089458565	-0.0626719558914	0.0678336863001	0.0216101271868	-0.0441678614433	0.0898875934686	0.0433055544993	-0.0640965139435	-0.0537477506827	0.01503313451	0.0382107203513	0.0136631324274	0.0284624783004	-0.000653795265724	0.0295277988337	0.0150541115252	-0.0184429425753	-0.0369019711132	-0.0117594290455	-0.0161694800713	-0.0138558687613	-0.0482063065596	0.0150987596982	-0.00 [...]
+449.F33Fotl	-0.172130365246	0.14368792585	-0.162128375393	0.22716536098	0.014857487991	0.0536358432782	-0.0899085554441	0.00113439430409	0.0173252988597	0.0707872046533	-0.053231139741	0.0402382086247	-0.000306021841041	-0.0521203208521	-0.109636307328	0.0500352953834	0.0147151727378	-0.0527848580933	0.0240471193835	0.0447629353751	-0.00215899710797	0.0170499462243	0.0263090861988	-0.0215709117076	0.00230633119798	0.0144293157787	-0.00496369478342	-0.000257284309331	0.019497290153	0.0052 [...]
+449.F34Fotl	-0.191838347812	0.170106077918	-0.139099190306	0.229335787304	0.03446453572	0.0119458186523	-0.0447709548659	0.0210028556951	0.0494784705161	0.101133640781	-0.0737432494201	0.00769108510883	-0.0505149863843	-0.0422613249406	-0.0315978106977	0.0358503591174	0.0299704319607	-0.0271188211619	-0.0397575165478	0.0281973921878	0.0116929294483	0.0391111827584	0.0453247286915	-0.00572288184817	-0.0409744694068	0.0396986705724	-0.00159305238636	-0.0183912264741	0.0263185073877	-0.0199 [...]
+449.M11Fotl	0.13180945512	0.110052084976	-0.0780725713801	-0.0612526178119	0.107840480065	0.0896713489807	-0.200937406278	-0.0906577113155	0.0757307815769	-0.170861421118	-0.00077573984179	-0.030078490935	-0.0171485002172	0.0701797773772	0.0126963141047	0.0387674346817	-0.0175916433486	0.0579302343205	-0.0909751408083	0.0402244100615	-0.00279492228938	-0.0202021430769	0.0450239054932	0.0719190377955	-0.0364098639544	0.0265712708512	-0.021048795483	-0.012670411169	0.0181972087663	-0.00415 [...]
+449.M22Fotr	-0.148178537655	0.147066722563	-0.179774912518	0.218977856879	0.000918550300187	0.0428484973208	0.0106341618774	-0.0145062765131	0.111145464048	0.0985243103619	-0.00233243732155	0.0472208786735	-0.0590425871105	-0.0726600447674	-0.049364924065	-0.0122097764451	0.0282087450196	-0.0507234132881	-0.00781478646979	-0.0258100670106	-0.0286214179007	0.0205623908967	0.0381706454466	7.6338537963e-05	-0.0255689548589	-0.0210420865698	0.014549695565	-0.00585074987626	-0.00227409489436	 [...]
+449.M42Knel	-0.153898580098	0.153217192059	-0.129904728596	0.0372350880615	0.0353059485422	-0.0195678558793	-0.0387349770692	0.0610034047075	-0.0169697192422	0.0198939233171	-0.0420935005067	0.00140780529124	0.0443525829612	0.0483405569973	-0.00442792182241	0.0179982872234	-0.0263896754628	-0.00896871241284	0.0167030899995	-0.0398072484618	-0.0186834360944	-0.0220099782033	-0.00248297777045	-0.0478733664417	-0.00326430540781	0.0699431514671	-0.0122456324928	-0.00524909645238	-0.025054767 [...]
+449.M21Fotl	-0.164863878969	0.0893765547457	-0.193870220143	0.110449817122	-0.014526257334	-0.0521202755734	0.0192528179398	-0.0103273657616	0.112649771359	0.0443402995554	-0.0282383800697	0.00815502013865	-0.0593175026464	-0.026181387651	-0.00339807168766	-0.0163136098022	0.000268235035795	-0.0272667846121	0.00588389377948	0.0121649831572	-0.0557023018545	-0.0167102326881	0.0352530109992	-0.0277907472443	-0.0177518432017	-0.00380797646143	0.0693450809547	0.0139774032923	-0.0137024827183 [...]
+449.M21Fotr	-0.124161642002	0.209338665559	-0.14980913568	0.193334265302	0.0177312872168	0.0639542183024	0.0185981913853	-0.0251755596611	0.090238555907	0.0533379982234	0.00969596596876	0.0367499293504	-0.046832834541	-0.0648906618673	-0.0269739452844	-0.0295955914379	-0.00583890663284	-0.0471830435087	0.0210612362385	-0.0197226711819	-0.042870397813	0.02329696834	0.0254898383346	-0.0194314169502	0.00397388524141	-0.0563314451657	0.0226344642946	0.00625094151992	0.0155262024615	-0.007743 [...]
+449.F31Indr	-0.186767361752	0.1470351733	-0.0346139387863	0.00401953142258	-0.0208477632592	-0.089415957684	0.0501044612729	-0.00588038866615	0.0120090777418	-0.0554692369083	0.027831619416	-0.00822133622253	-0.0841090498816	0.0358020763847	0.0537384976837	0.0674572048387	0.00688004910189	0.0241980627687	0.0569716795616	0.00516474402275	0.0128132722021	-0.0465238055139	-0.0208704994603	0.03771751257	-0.00823535917713	0.0421356205003	-0.0310750214286	0.0334537661971	7.63620253359e-06	0.02 [...]
+449.F14Fotr	0.0353959679549	0.168145031035	-0.0580870859696	0.126495596835	-0.0733488424583	0.178382261257	-0.0160657033446	-0.133828194892	0.126857884798	0.00494435695524	0.0456382210655	0.0209695669869	0.11490426394	-0.000172155707624	0.0299903014102	-0.0229921516419	-0.0699700709203	0.0362330813222	-0.116817238872	-0.0596055846716	0.0167123417725	-0.0134637706761	0.0648457579705	0.010048528111	0.0945910192535	-0.0304484150158	0.00235482382891	0.0282722262088	-0.0314908658725	-0.009155 [...]
+449.F13Fotr	0.18429805397	0.1066132104	-0.0386622193602	-0.0524978823266	0.0762333429151	0.102504201498	-0.0113517848628	-0.0367513458698	0.13300400727	-0.00649521729041	0.0718487224992	-0.0110241704017	0.137739495979	0.0309619575402	0.00427035532221	0.0143618987323	-0.0446184050928	0.0641761154968	-0.0952319099333	-0.0295524893071	0.0604642047515	-0.0435367780426	0.0815533486324	0.0517770868146	0.0547178592405	0.00710606654322	0.0741730067123	0.0040664889272	0.0300202073452	0.0718837477 [...]
+449.F12Fotl	0.220586493452	0.0531715567071	-0.0601693414143	0.0297133402921	-0.113619849022	0.0913135960977	0.0862294243533	-0.0378014866957	0.200270850267	0.108887209951	0.0552287347956	-0.100887247583	0.0382936058738	0.0456285577694	0.0340309667743	-0.168433434252	0.00406261737477	0.0316955647866	-0.0387835903629	-0.0267538627686	0.0192192692326	0.00885936890084	0.0431784089475	0.0373744155857	0.0198753552976	0.0954657302901	0.0405799777837	0.0435328970751	-0.119606693288	-0.0612928239 [...]
+449.M42Glns	-0.0254330978624	0.204051701465	-0.0459967725516	-0.0572416885411	0.0774467046488	0.0155165104633	-0.0535756647809	-0.0111690524887	-0.0523863175177	-0.00888071188215	0.0549861033671	-0.0134955569776	0.0687297243107	-0.0419369081307	0.0831661088537	0.0718190764305	0.0147190985671	-0.028100455208	0.0317270791766	-0.116357639617	0.0361875716801	0.0195584761356	-0.0145718063793	0.0224150203609	-0.05898044178	0.0231021864093	0.0220981765725	-0.0137250221985	-0.00124306999542	0.02 [...]
+449.M64Plmr	-0.177376788162	0.111357855826	-0.0409290470955	0.0755131386132	-0.0118634491306	-0.00731744033209	-0.0128698346974	0.0343335252731	-0.0196084705082	-0.00284637603858	-0.0101288702234	0.00585995419956	0.0599795672094	-0.0479613078363	-0.00112809597621	0.0148471038025	0.00488751375599	-0.0338711249701	-0.0400191006956	-0.00634429685567	0.00545780481766	-0.013884331685	0.0113283882554	0.0243442950793	-0.00482291365164	-0.112057308868	0.0507895464661	0.00387754632703	0.007276972 [...]
+449.M32Fotr	-0.142378356775	0.176676701395	-0.176196835436	0.160134458964	0.0431482135787	0.0425032188302	-0.0612293327055	0.000684636254037	0.0589500557184	0.0730510561837	0.000439299712099	0.025795604645	-0.0565680858189	-0.0519109480018	-0.0308107669405	-0.00464047346784	-0.0155616924938	-0.00163197464058	0.0322254114701	-0.0320553104526	-0.0414268493972	-0.0127435992016	-0.0274408305458	0.00726384398582	-0.0528670567717	-0.0399928077353	0.00259520035185	0.0547327152908	-0.01150669891 [...]
+449.F34Plmr	-0.00859298185163	0.237401909969	-0.0874697436672	0.0184015051899	-0.0128183981928	0.0559999171302	0.0186299435868	-0.0869735040006	-0.0532497963604	-0.152008351495	0.00657144516675	0.0962329055836	0.0171501410654	0.022665911187	-0.0339980509236	0.035029383451	0.00130115087956	0.0182280583407	0.0704470707057	0.0244729656529	0.060397152128	0.0688313487671	0.0116258466636	0.0296075525812	0.0101700914503	0.105331271513	-0.0202651029665	-0.00387226209142	0.0474955377322	-0.035702 [...]
+449.M23Frhd	0.18023158357	0.156091322202	-0.0198752732997	-0.0409090808079	-0.139161963899	0.055815774019	0.0323931132411	-0.160239071783	-0.0755349191503	-0.185130975895	-0.0331768564685	0.126751659393	0.0207901295836	-0.078745075183	-0.0242581264106	0.0291064387948	-0.013938945846	0.0359508729777	-0.00190645086401	0.0303308503203	0.00808200719314	-0.00790877014032	0.0456659224116	-0.0203043489518	0.0361719762846	-0.0117583121005	0.0616428842566	0.0651588221785	0.041310959919	-0.0278373 [...]
+449.F13Plml	-0.0855934821988	0.235761219651	-0.0576762268954	0.0577852638485	0.0102654369527	0.0742830321103	-0.041445420804	0.00617396521802	-0.0248764002989	-0.0166088299673	0.0490558076626	0.0426495875082	-0.00964733036921	-0.0312038065278	-0.0166151008937	0.0965874311338	-0.00957463607966	-0.0252807220362	-0.0181735482126	-0.0292159444713	0.0280869117904	-0.020231811165	-0.00395944910529	0.00826840897691	0.0211300652379	-0.0901068234362	-0.0326316284802	0.019648627159	0.0454304335478 [...]
+449.M43Nost	0.00326333275678	0.074037129696	0.129612718319	-0.138193971594	0.0337137195507	-0.0376058678271	-0.0151867166668	0.023464552555	-0.0422689174464	0.107384667402	-0.0319442763559	0.0169191592738	0.0725775066319	0.0251803942056	0.0794877580818	0.0525176056924	-0.00608363598828	-0.031616705962	-0.0785107960979	-0.12050357104	-0.0751578963656	0.0147387518323	-0.00992062023099	0.0383655789192	-0.0301172752978	0.0268434809742	0.015074192912	-0.0594180911372	-0.0439968142434	0.001570 [...]
+449.M64Knee	-0.143474829622	0.0820859808657	-0.215636676761	0.0449476236183	0.0263446991997	-0.0301894474224	-0.0906397088414	-0.0300600162229	0.0567696756132	0.0133062280934	-0.0364148111139	-0.00634075829955	0.0397931781161	-0.0895014771722	0.053761808301	0.0651442873343	0.00365175579712	-0.0407653087219	0.0402681465767	0.0336785631417	0.0490165850569	0.0426484201541	-0.0283030002273	0.0123804431522	0.0163613061921	0.00834557153561	0.0201755507326	-0.0712221487298	0.00892438303245	-0.0 [...]
+449.F33Nost	0.117462591572	0.126930428179	0.0234872366765	-0.161232700808	0.0485563048503	0.0211084411046	0.0058522774285	-0.0538344103686	-0.0250849232788	0.013385200698	0.0117014450264	0.135748034594	0.0377076923404	-0.0866878164744	0.0602252541903	0.0232773740433	0.0432604059672	-0.0288314528462	-0.0467777660285	0.010560724979	0.0213349296821	-0.0193780921994	0.0110577270964	0.00407804579673	0.0329176742611	0.018476748785	0.00129742952346	-0.00642879098427	-0.0279532458348	-0.02389726 [...]
+449.F23Frhd	0.268578235372	-0.00175023127873	0.0489196197587	0.0112018253748	-0.111387580211	0.0312798048545	0.187981447554	0.0349888798197	-0.00897529823922	-0.0146785384981	-0.212973777784	-0.101457278969	0.0676189391905	-0.0446219812437	-0.0535855200592	-0.0274766087283	-0.0388397287614	0.0276112831377	-0.0814358488251	0.0470259182461	0.0177751303727	-0.0302392171616	-0.0265650261514	0.0293969164	-0.0715735904076	-0.00984649030897	0.000921031859636	0.0199835248951	0.00145973334083	0.0 [...]
+449.F13Knee	-0.113160597261	0.209701438788	-0.122308255537	0.0694494537065	0.0733944058596	0.0395530503437	-0.0269731490844	0.00924109760785	0.0146764173006	0.040177695613	0.021734165338	-0.0275570351736	-0.0464025546432	-0.0374057016126	0.0461553300394	-0.0268505366408	0.00744143394565	0.0705797157173	0.0205466605744	-0.0107476993075	-0.025985497313	-0.0432945397166	0.0360344886024	0.0189166753668	0.0635440232376	0.0181048083819	-0.0454223852907	-0.0163090148274	-0.0270302313221	-0.0459 [...]
+449.M44Frhd	-0.00452040804702	0.155511194423	0.0797849568198	-0.119678870094	0.0319476327909	-0.0119660515034	-0.0216595974109	0.0203295259416	-0.0332254149458	-0.0151925845417	-0.0371782969423	-0.0600817324924	0.0649130943587	0.0302661211115	0.0716105830493	0.0676337252803	-0.0544183888184	-0.0406237905432	-0.085035603261	-0.0612723480821	-0.0822225020491	-0.00887642189914	0.0409932105415	0.0136535888723	-0.0655571417135	-0.0329780125368	-0.0278346857394	-0.0286119227876	-0.001633387500 [...]
+449.F34Frhd	0.091961126538	0.190424900341	-0.0171399624385	-0.120223521564	0.031823059848	0.0233615131448	0.0340719283835	-0.0661680715058	-0.055293595061	-0.102785641804	0.0636196921172	0.132179579075	-0.00300380402925	-0.0507705632658	-0.0210145286696	0.0896284993184	0.0747959874673	0.0168611526991	-0.0249617829487	0.0113089876959	8.83798617425e-05	-0.0130632773764	-0.0105778676926	0.0168244767882	0.0274923993911	0.0271304303838	-0.0513945244729	0.00204901563791	0.0147679528333	-0.0325 [...]
+449.F14Frhd	-0.0651839916875	0.0877193306521	0.131204123439	-0.0799671472025	-0.0106541869102	0.000183708546728	0.0480902826817	0.0151439985345	-0.012208425637	-0.0657802862819	-0.0574721582925	0.0394142859893	-0.00957792281584	-0.0104828070527	0.0771107315654	0.0883682744382	-0.0723382940676	0.0173398854726	-0.0471648932417	-0.00710520966684	0.0711928154008	-0.0355673269748	0.0211117816251	0.0450035375673	0.00186811641324	-0.0314186145207	-6.89819699444e-05	0.0526333885979	-0.0141738459 [...]
+449.M44Ewax	0.394114238797	0.0159060380801	-0.0189065848186	0.0195439237596	-0.0486927263193	-0.0820407707168	-0.188599540465	-0.0371857925954	-0.0906659994829	-0.0366608953997	-0.0745223365253	-0.0227518224991	-0.131544503312	0.0423671927055	0.0270718991904	-0.00743171176686	0.0610239778516	-0.00378470809617	-0.00597220835974	-0.051889181648	-0.0782898246212	0.0104263456909	-0.0294496913084	-0.0219827052305	-0.0400419545587	-0.0225927482393	0.00255788942596	-0.0243044719563	0.0111904861 [...]
+449.M63Frhd	0.229953108508	0.15404006723	0.00160096100362	-0.138767973555	-0.0102001999716	0.00277692492601	0.0429360493245	-0.0429600507188	-0.0955791714293	0.0132172909889	0.0560820060118	0.00538241665334	-0.0119807650677	-0.0510552932951	-0.0702334037686	0.0795998582479	0.0400400676771	-0.00886766093879	0.011433739361	-0.00999137456848	0.0357129673128	0.045611898506	0.0229630320082	0.018124673683	-0.0195953495557	0.0437568370249	0.0861948843814	-0.0101587889922	-0.015702485025	-0.0165 [...]
+449.M24Nost	-0.00666469588456	0.0641786734048	0.0382517168762	-0.135870235906	0.0813040065002	-0.0431793622837	-0.0383628082841	0.0111580249533	-0.0695418461003	-0.0525449599097	-0.0974708617623	0.189361801833	0.0129734912282	0.0174545710501	0.0769393742928	-0.0585200024079	0.0365146111823	0.0388281485424	0.0460795643383	-0.0469875449859	0.057580043747	0.0319345143105	-0.00313466132069	0.0117790135817	-0.0272490054633	0.0700509685183	-0.0038440772491	-0.0738585960473	0.0961323862464	0.01 [...]
+449.F34Nost	0.169028419547	0.130863244622	0.0307165002863	-0.126266307679	-0.0735676541697	0.0482068048989	0.00136467424709	-0.113113787133	-0.0588152336522	-0.0341393806877	0.04494208014	0.167301470834	-0.0419217387131	-0.0118788923112	-0.0570102690666	0.0376710146739	0.00066302788779	0.0389114459739	0.0751121914724	0.0130408097531	-0.00530630151012	0.0846632185318	-0.0261365058315	-0.0302515466939	0.00791178701459	0.0577434625835	-0.0228614447127	-0.00929677742027	0.0126460689088	-0.04 [...]
+449.M24Knee	-0.184100767025	0.0295487890357	-0.217680683525	-0.0042356600088	-0.0187207214654	-0.116278829749	-0.0257584939899	-0.0252609673447	0.0970003337391	-0.0478250208896	-0.013356955854	-0.0284870417465	0.00929896238587	-0.033672434695	-0.0031478396354	-0.0533799883002	-0.0235837827613	0.00424761934551	-0.0122100183246	0.0305952469021	-0.0432539046141	-0.0125391825485	-0.00771580522217	0.00493554332306	0.0448328514449	0.0274440882561	0.0127672789935	-0.0224281897607	0.005513954975 [...]
+449.M64Frhd	0.246892615868	0.0730160590292	0.0118353452824	0.00144677824504	-0.169574962191	0.0523126726043	0.182722177144	-0.0608348578542	-0.0281579657927	-0.0275149985796	0.0470332548507	-0.0790997802492	-0.0773434632249	-0.129458445485	0.0191706552932	-0.0651150234891	0.0451878025545	0.0295415806364	-0.0560535266158	0.0402774643954	-0.012036530846	-0.00248993152868	-0.0567073016489	-0.0267402066479	-0.0414170127005	0.00506339546943	0.0165136405285	-0.00370760781876	-0.0532762608397	0 [...]
+449.F11Pinr	-0.00215942421202	0.146147460416	0.0611220114176	-0.0823484399583	0.058195356112	-0.00171387894591	0.083827658066	0.0746559652901	-0.034838458768	-0.0416272086819	0.0169343151105	-0.10266240946	0.0656344004974	0.0412610965328	-0.0294179696402	0.106539608751	0.00877115049485	0.00566749862638	-0.0656469210357	-0.0499327084385	-0.0419196800346	-0.0150273523891	0.0556982441312	0.0035981109029	-0.0143797624077	-0.0387968664315	-0.0241690347655	0.0164306893516	0.0309265080631	-0.02 [...]
+449.M44Nost	0.00440239565561	0.0440375461551	0.175578905988	-0.166675103606	-0.0534607654807	-0.0482212702968	0.0106270603885	-0.0137561106004	-0.0355257942667	0.0847196101657	-0.0756891752544	0.109577457349	-0.0134870833787	-0.00245408724992	0.0816585580383	0.0593329584944	-0.0357357337967	-0.0131513803073	0.00911520701074	-0.0670047138247	0.00104639552009	-0.000478587980668	0.0362900257208	-0.0211333086686	-0.00741699292059	0.0196936559948	0.0374849948623	0.0203853275591	-0.06004780403 [...]
+449.F13Ewax	0.43075336528	-0.120484995245	0.0327468478614	0.225578682555	-0.149897230763	-0.0579156985367	-0.02341578349	0.139244779425	-0.0444216625503	-0.0774168024813	-0.0414602854956	-0.0131710764309	-0.0575408711759	-0.127732568959	0.00764520389209	-0.00175053880304	0.00593419892857	0.0688362264673	-0.018040573927	-0.0227827842822	-0.00490410996135	-0.0183781171378	0.0179873101667	0.0127149169491	-0.0205150229244	0.00962100338265	0.0291288278992	-0.0258659176554	0.0339842129473	-0.0 [...]
+449.M31Pinl	-0.0193618111692	0.147980486741	-0.0351919475367	-0.0820459424817	0.0182043407027	0.0227113523963	0.0484816577089	0.0101488987444	-0.013364536703	-0.0791454420984	0.00813228009599	-0.0272439616797	-0.0466751941802	-0.0103651672892	0.0280340983112	-0.0315830347111	0.0675347134693	0.0313936324653	-0.0452248028258	0.0105060490635	-0.0649396620003	-0.0467673123259	-0.0277226454005	0.0263981058836	-0.0440563584812	0.00462607854509	0.00140336029643	-0.0347284752732	-0.0819527231824 [...]
+449.M32Forl	-0.154740776228	0.14236353907	-0.0531484702086	0.0409917476341	0.0266982259829	-0.0120630169069	-0.045786996849	0.0270484097956	-0.00636559515247	0.0386853760536	0.0611550089813	-0.0397264927353	-0.0398622769757	-0.0772697783033	0.0209937921785	-0.0437643184007	-0.0552299945181	0.00299733685482	0.0442812947518	0.0321232205774	-0.00348318304308	-0.0557970731373	-0.0526740627532	-0.00416613078567	0.0113953471643	-0.0628058038494	0.0498906627615	0.0371114671176	-0.0181975187503	 [...]
+449.F12Nose	0.00177443714038	0.190408630348	-0.0151476267332	-0.0390764332424	-0.0109197626407	0.0496016783092	0.118628860711	0.0545060951597	-0.0479826881036	-0.0623622822677	0.0133586474947	0.0220326654394	0.000916612212572	0.00671612064915	0.0136946675215	-0.0952054943448	-0.0462310139633	0.0133706144478	0.00381948873475	0.0135700681351	0.0315935418143	0.0513922754894	0.0272539623673	-0.0547373124384	0.0272039865819	-0.0585204531848	0.0651131201857	-0.0214794876314	-0.0464359977635	-0 [...]
+449.F12Pinr	-0.0849393106267	0.185037345138	0.00989654900908	0.0215129583689	-0.016897522579	0.0843736058759	0.0536198025914	0.0232493219297	0.0466139136658	-0.0408269990077	0.0362977259365	-0.0337995387671	-0.0053583688148	0.0606858303022	0.0489043555162	-0.0391922489381	-0.0201480634666	-0.0228872697691	-0.0503577278739	-0.0146767960401	0.000655053122751	-0.0368279810656	0.0258970023374	0.0123559289973	-0.00502323099253	-0.0729780419223	0.0255946590671	0.0323184494376	0.0287579057782	0 [...]
+449.M31Pinr	0.156930517476	0.115375141979	0.0512087857499	-0.0833246011561	-0.0215052369959	0.00831670647794	0.0753163446556	-0.00270640354923	-0.0353187970725	0.0352318837654	0.0807208813337	-0.0905959192339	-0.0174420432756	-0.0202680159348	-0.101282783888	0.0781495862871	-0.0984156250515	-0.0546421895665	0.0766600971927	-0.0654665374137	-0.0381123266169	0.0705130808762	0.0154704048697	0.0236148935226	-0.0120312773552	0.0691624027731	0.0316038764244	-0.0466974385723	0.0645272136998	0.0 [...]
+449.F22Pinl	0.302011380726	-0.052804029485	0.0550295037071	0.0592676348838	-0.034815551713	-0.0260314662488	0.0418107096664	0.135674867452	-0.0305073216368	-0.0865193352056	-0.224847344586	-0.0820972211589	-0.0520426023189	0.0322804986016	-0.0418575099578	-0.0897427660086	-0.00975154513699	-0.0499471710665	-0.0464953396431	0.00975482182284	-0.0343492433982	0.0497287530023	0.0149750683794	-0.0398728702539	-0.00200377225556	0.0908383386984	0.0132325544117	-0.0115387456508	0.00349748513315	 [...]
+449.F21Knel	-0.150360970186	0.1395193334	-0.0460690729616	0.0155508327035	0.0758514652182	-0.0149679799652	-0.0364190418039	0.0201369282537	-0.0214994740932	0.0361563945675	-0.013049255218	-0.0415427762143	0.0902942505715	-0.0495463378937	0.0772707229792	-0.0417861504738	0.0289659154351	-0.0213013870706	-0.0164303470695	0.0426324189093	-0.051415092959	-0.0227888951234	-0.00237947347339	-0.0575694588995	0.0627170475188	-0.0827567329587	-0.0566649796277	-0.0217856221709	0.0464330913081	-0. [...]
+449.M32Frhd	0.0980318380119	0.0976853345968	0.0616080306738	-0.0659140475817	0.0128210604567	0.0631626647139	0.0561926153705	0.0255912542286	0.00856952840157	0.0279333143528	0.0884420634717	0.0880332279646	-0.00788006291543	-0.0862926282068	-0.019230081722	0.0690731729198	-0.0697653443164	0.00250974021249	-0.105943935677	-0.0558577133343	-0.0868822149637	-0.0463545909397	-0.0410691753944	0.00915291575512	0.0338642992059	-0.0663419112542	-0.0448120639439	-0.0244873228919	-0.0192027666718	 [...]
+449.F22Ewxr	0.448636572787	-0.128078649237	-0.00064038850151	0.308921690019	-0.0533745143653	-0.162056007123	0.00312454899539	0.128747912808	-0.0862197979614	-0.062927223574	0.0327781072122	0.000838729832472	-0.00600873143261	-0.0357655187169	0.0762334140364	-0.00983254251087	-0.0220320796999	-0.0158397229486	0.0107786504333	-0.0361342286243	0.0268195246859	0.0133836962423	0.0187455486361	0.00969454281696	0.0409747111162	0.0153261468636	-0.0243510128546	-0.0620954703336	-0.0134142291645	 [...]
+449.F12Navl	0.316172020477	0.0569609961771	0.0353679051894	-0.0638564300488	-0.0996248044121	0.0228736859578	-0.0382373788489	-0.105582784074	0.0269783399813	0.0457223614818	0.011584055904	-0.0186607564657	0.00973012569237	0.0420565916455	-0.0846575867074	0.0530753706642	-0.0177743401721	0.0526590863007	0.0513322651762	0.00618458187877	-0.023104628411	0.045454632522	0.0283753077145	0.0410776143372	-0.0676460665717	0.0368191546877	0.086800459408	0.0686681098865	0.0973868538903	-0.04258636 [...]
+449.F32Hair	0.13694862737	0.136041900822	-0.0572989453573	-0.0459534030121	-0.0456868781567	0.110612118663	0.152131078362	-0.0634440042456	0.0315587489172	-0.0441523238568	0.135197312017	-0.0558542841249	-0.0818047686983	-0.0722174542939	0.00562462962122	-0.0252315644561	0.0618999927742	-0.0297964156751	-0.0255321292046	0.0301073719505	0.0484124574166	0.112681614459	-0.0169440410381	-0.0807700198907	0.00063696211516	0.000722756654374	-0.0197469932627	0.0282601479397	-0.087844511264	-0.06 [...]
+449.F31Forr	-0.114802546603	0.182675467558	-0.073471796896	0.0665876215166	0.0362922593914	0.0391645043404	0.074190033479	0.011721788161	0.0118067276878	-0.0288682960796	-0.000409982371604	0.0119998001022	-0.0539496133381	0.0377214826075	0.0021772323228	-0.0379795875011	0.0712725504128	0.0324698454114	0.00447374932113	0.0495750513872	0.0298870826062	0.0265238914914	-0.0182615401791	0.04656654435	-0.0196963171536	0.0831546645696	-0.0470310422173	-0.0397498181127	0.0400244935604	-0.0342485 [...]
+449.M22Ewxr	0.0206646500177	0.0589992317542	-0.0805555918349	-0.167899697351	-0.060810828528	-0.0532736729424	0.0745945267785	0.0743033539696	0.0222939784492	-0.0429620133392	-0.0410439963123	0.00558448989842	0.0590809655312	0.0328107960931	0.0277417619446	0.0407200445341	0.0491110726521	-0.127622322583	0.041083894082	0.0233284857166	-0.0140977378599	-0.0642615051	0.0229039877198	0.00033308430001	0.0309611741538	-0.00187888381072	0.0290383821332	-0.00308094764226	-0.0265212826186	0.06170 [...]
+449.F31Knel	-0.0258820420758	0.194306832357	-0.084598387349	0.00328861109605	0.0651701579055	0.0566943439045	0.0911790421998	-0.0238600297763	0.0387731184534	0.0250777796618	0.0672824860207	0.00678731636235	-0.0300378794334	-0.0587171684265	0.021301984341	-0.118533051559	0.0580804914856	-0.0167176694015	0.037878080954	0.0659928538042	0.0309302184954	-0.0339857677725	0.0486626956416	-0.0144276058181	0.0318864608425	-0.079867292779	-0.0286742643926	-0.0342395846922	0.0775641581844	-0.08338 [...]
+449.M22Navl	-0.00719706974589	0.0495594990349	0.0156910977616	-0.156094870225	0.0157715789543	-0.0654569984096	0.0916766071541	0.0142035875987	0.0595410357647	-0.0523766377459	-0.0203938503926	0.015152548363	-0.0264199651231	0.0114218873104	-0.0275996040665	0.0439866559632	-0.0424175087233	-0.0209906991216	0.0888365675922	-0.0720287738155	0.0245147388735	0.0118540954762	-0.0677630118442	0.0534825995579	0.022939794416	0.0308032642166	0.00401082713686	-0.0357601824663	0.00676379098378	0.04 [...]
+449.F31Frhd	0.0284707020923	0.128995085649	-0.0164322078696	-0.0583216319458	0.0754532887057	0.0509783080723	0.199657540079	0.0416388965833	0.0460025266019	-0.0524325423612	0.0244533024525	-0.0746084914988	-0.0575479111946	-0.0315222804457	0.0175385004604	-0.0661207827098	0.0739057231671	0.0112884513511	-0.0871891678628	0.0942094204787	0.0249352631423	-0.0262238837344	-0.0258318745497	5.12277931315e-05	-0.0109620148436	0.0258119942139	-0.0189847340881	-0.0711816383061	-0.0212572495113	-0 [...]
+449.M22Fotl	-0.157477786071	0.146679903326	-0.185484523973	0.190249913907	0.0112639888124	0.040766927434	0.0410601032369	0.0321102978552	0.0979449607516	0.0713258490821	-0.0492787167792	0.022542870562	-0.0334383983007	-0.0347938826564	-0.000781269447831	-0.0162371613965	0.0453867727367	-0.0442293982292	-0.0222686928737	0.00804816302303	-0.0375570095369	-0.0176927215721	0.0279708244581	0.00911100357364	-0.0291457778182	-0.0181936004203	0.0624350427034	0.0236573769331	-0.0032701409791	0.01 [...]
+449.M21Aptr	-0.0481946210167	0.0521492961212	-0.115186319302	-0.0957909217902	0.0303821352483	-0.0112972247213	0.0455232689881	0.000680966476441	-0.00540948381119	-0.110207905518	0.0331561713422	-0.0230918815033	0.022748754969	-0.0615321150046	0.0427091393814	0.0962679960281	0.0280004081086	-0.0406124491215	0.111263406243	0.0580314518142	0.0630868593854	-0.0225145155451	-0.0155567787842	0.0335548920127	0.0110857553494	0.0338342756446	0.0882959339823	-0.00490406912042	0.0142266423775	0.02 [...]
+449.F32Forr	-0.0974098866935	0.154830480315	0.0282842537532	-0.0300481342616	0.0183843364115	0.0162945470189	0.106243057118	0.0141298796013	-0.00445681975901	-0.0366215599973	0.0555289509442	-0.0139779563726	-0.0455410796993	0.0117020817405	0.0167695158005	-0.0079810005765	0.024369493065	-0.0236982790967	-0.0141743677151	-0.0218097960129	-0.0407104386259	-0.0951132965481	-0.0339177124726	0.0629826725239	-0.00784303288089	0.0412828681312	-0.0586956744228	-0.0137372932823	0.0786607267357	0 [...]
+449.M22Frhd	-0.0898791558841	-0.0593485007333	-0.172128213905	-0.168774730659	-0.0594519761925	-0.232451096263	0.071308145253	-0.0198311119488	0.106658650231	-0.0450588074938	0.0351993784768	-0.0178878227498	-0.0368516443102	0.0103395167077	-0.00142037479557	-0.00830126743522	0.0126176548993	-0.0165269224942	-0.00453232811119	0.0287683365648	-0.0149846328046	0.0059403982914	0.0126907302836	0.058727986426	-0.0432564695738	0.0302440509378	0.000320777882915	-0.0461619705304	0.0299894791317	 [...]
+449.M41Plmr	-0.177792232124	0.147686828298	-0.035144008055	0.0490359387632	0.00819526037842	-0.0538195304943	0.0259812934266	0.0100565424445	0.00806955348565	0.0530105260732	-0.00259208798133	-0.0268103504799	-0.0676906620901	0.0525314306257	0.0800702830654	0.05472202042	0.033169839672	0.00821789773009	0.0258248408291	-0.056841590148	0.0139191616706	-0.0126042571249	-0.0228195704278	-0.0370692457428	-0.00777787619837	0.0516218691647	0.0451524111438	0.0327504312281	-0.0392357586557	0.1103 [...]
+449.M22Pinl	-0.113991106693	-0.0113864126888	0.0144129589486	-0.154105162214	-0.0744832623645	-0.146336139977	0.0742313472796	0.0210105098357	0.0715127056153	-0.0162938806154	0.0487780337395	-0.0326464059623	-0.0669419324871	0.0210716799638	0.0149414110196	-0.0203097256747	-0.0232129621476	-0.0263056070965	-0.000164499678588	0.0429379078318	-0.0441558161175	-0.0448722267817	-0.032554645021	0.0157432005489	-0.00272605718254	0.00624120373102	0.0127672882218	0.0494695068258	-0.0139952122356 [...]
+449.M41Pinr	0.12443701109	0.129246454623	0.0205452551622	-0.0858695721487	-0.016682261769	0.0307479129245	0.0701184655473	0.0627817697075	-0.0295336568265	-0.0297148458746	-0.0763468456623	-0.100907506088	0.0781314491802	0.0557544598663	-0.0517802808258	-0.0716663560273	-0.0492770370909	-0.0218747271949	0.030395940922	-0.0105275374347	0.0203168890703	0.0693466483914	0.0258463461043	-0.0389491320871	0.0219340838915	0.0755475164568	0.0447814041801	-0.0420481792748	-0.0843192951456	-0.01708 [...]
+449.F31Fotl	-0.131652562274	0.192109321891	-0.156749370114	0.185703262666	0.0362265661777	0.0484341626639	0.022219842723	-0.0298999583064	0.151292496542	0.0602451270065	-0.0214478334599	0.00414555556786	-0.0835950584884	-0.0508889213387	-0.000491564046223	-0.00724732067135	-0.013334525097	-0.0348912710469	0.00439697203378	-0.0119287135958	0.00136652973474	0.0160433465912	0.0317304239544	0.0104671491983	0.0155867461116	-0.0113371643518	0.00905291458363	-0.0264832040772	0.0101183551123	-0. [...]
+449.M21Pinr	-0.134278398943	0.0076438846804	-0.060435961814	-0.0178683516774	-0.0643840490033	-0.0985025388116	0.134697429151	0.0249603641059	0.119059935372	-0.00911126497966	0.0504747580837	0.0040157020116	0.00312248946687	0.0399046107513	0.023086039339	-0.0248845134274	0.0104217824227	-0.0399491707886	0.0531736772529	-0.0729321981461	-0.0235441925581	-0.00824292343064	-0.0334983302218	0.0503604014503	0.0187387643222	0.0204471322439	0.0464739238835	0.0293171397843	0.00805473488464	-0.00 [...]
+449.M32Indr	-0.0859075081125	0.135550098048	-0.0130506045041	-0.0610964532215	-0.00177967714886	0.0146730916267	0.035729220847	0.0225894827201	0.00722619256832	-0.0496203737426	-0.0361310855857	0.0537057155252	-0.0466581651365	-0.00205084188597	0.029056964027	0.0796748552264	-0.120019862434	-0.00772683792446	0.00280198276436	-0.0194928844047	0.0328507386135	-0.0100908664081	-0.0874168939868	0.049995553526	-0.00232584631748	-0.0561640005793	-0.039764602667	0.0296836893555	-0.0030139542695 [...]
+449.F13Tong	-0.170127885863	-0.200679117443	0.365897068662	0.0388307744147	-0.0102104396615	0.037211936831	-0.0129742719458	-0.0451431318954	0.0672705582971	-0.0162351978811	-0.0324958075162	0.00384753236973	-0.0421341196983	-0.0017254511444	0.0283838331591	0.0329079546614	-0.0326163015466	0.0132382609716	-0.0133425817779	0.0189096655758	0.028365170239	0.0164353874669	0.0146957803077	-0.0483305457016	0.00273201398407	-0.0331330986125	-0.0311123939526	-0.00239437096868	0.01019107484	-0.01 [...]
+449.M54Urin	-0.1866563183	-0.165152496597	-0.0226847492183	-0.0791274211709	-0.0565466476214	-0.0606411153371	-0.0596577745009	0.020456001723	-0.106164208937	0.0278332778739	0.0704456915485	-0.0393725464447	0.0922617261225	-0.0813769922218	-0.0798073873778	-0.0968399685038	0.0221030225189	-0.0862970164993	-0.0170937599717	-0.0202865197383	0.0686037960208	-0.103411297758	-0.0288120775519	-0.0160581373867	-0.0551722437594	0.0570866582722	-0.0715124736496	0.0607927983902	-0.00872216677124	0 [...]
+449.M23Fcsw	-0.123740222359	-0.369977018987	-0.267966355534	-0.103943071872	-0.0307890589589	-0.066584210877	-0.0256910943946	-0.00475655980669	0.0148984359082	-0.0186873228468	-0.0314326219919	0.0170341016682	-0.0241092856945	-0.0227645761722	-0.078760496593	-0.0683839865308	-0.0223077154808	0.0510393374678	-0.0309144729941	-0.0472566906968	0.00255738276635	0.0558319909593	-0.0691451559951	0.0525739536865	0.0492648869312	-0.0461863295261	-0.0397255416876	0.0127769891422	-0.0237739340022 [...]
+449.F24Fcsw	-0.0895093008859	-0.398247834219	-0.243540787881	-0.033410151968	0.00876477254971	0.149043384612	0.0493430330537	0.0304417820379	-0.0450816060877	0.00791275297814	-0.0431460385084	-0.0402981637439	0.00258930996442	0.0324955870437	0.0923326014809	0.0917313954291	0.0301846872089	0.021333374408	0.0027663758948	0.0571541410665	-0.0522525491914	0.0447040259037	-0.0916418749908	0.126728529522	0.10676036149	-0.0224352150122	0.0939660748337	-0.000354494606273	0.0258652777592	-0.04610 [...]
+449.F23Fcsw	-0.0664839885959	-0.383852277837	-0.256752705913	-0.0132848815598	0.0212405706955	0.207981189688	0.0292736628403	0.0482672692089	-0.0769354890979	0.0340711531812	-0.01043065495	-0.0480413916616	0.0170865006228	0.0574472785541	0.115276487691	0.0943890587022	0.0343242705802	0.00738504163897	-0.0173764024843	0.0530029981166	-0.0543243428677	0.0322092612316	-0.0755506584378	0.109291539837	0.12336461182	0.00868033664691	0.0878512552933	-0.0253734159277	0.0220183208915	-0.065621667 [...]
+449.M21Fcsw	-0.156779129949	-0.415979098753	-0.269316284171	-0.0616340705259	-0.0686499686008	-0.0926147107132	0.0383561751871	-0.0160851159569	0.0607163746076	-0.0496876472434	-0.0150758192637	0.0595443512794	0.000921515333328	0.0118649151253	-0.13124264359	-0.0664196274765	-0.00191541120069	-0.00269533854399	-0.0656672282781	-0.0620778274068	0.0365253667596	0.0609567574341	-0.0779041027488	0.00197960925187	0.00583962759671	-0.072510944281	-0.0300913230393	0.0155714821347	-0.02752860052 [...]
+449.M22Fcsp	-0.110703544331	-0.37678060614	-0.207642649502	-0.0638329336673	-0.0396234518406	-0.053446499643	0.0428869663668	0.0350953344926	0.0919002308082	-0.0579502511777	-0.0280440308051	0.0664544601438	0.0409974965331	0.0242455355603	-0.0983871237077	-0.0787421889087	0.0210035344747	-0.0381716307171	-0.0805972481267	-0.0287805390918	0.0406462273252	0.0661754830037	-0.130211988732	0.0166643960643	0.0109543367861	-0.0769905840304	-0.0205682901611	0.0709376777057	-0.0535112963423	-0.02 [...]
+449.M11Fcsp	-0.0933290347829	-0.401427953775	-0.29577872361	-0.0345542132199	-0.0141438810793	0.116641777349	0.0248238775998	0.025333504086	-0.0469625288815	0.0123482073072	-0.00957655526239	-0.0226078550632	0.00574930779507	0.0191459968068	-0.0105875456564	-0.00239244517501	0.0143423697599	0.0141304517853	-0.0286595065271	-0.0155422974842	-0.00115855036531	-0.0106727456582	-0.00128996111492	0.0736529647696	-0.00651095925856	-0.00692188445748	0.0453751290912	-0.00217574390313	-0.00853794 [...]
+449.M32Nstl	-0.0260740206096	0.137358017335	0.0175994460984	-0.0752059179818	0.00222152030332	0.0280369517499	-0.0642994130258	0.017785418738	-0.096661914248	0.0436882493403	0.0739008707428	0.0808701070573	0.0158674991296	-0.120260299295	0.0646002329822	0.0647264028859	-0.102775468756	-0.0346071006173	-0.0758753415416	0.0490277995618	0.0455786728585	-0.0136208627604	-0.0305709188944	0.033929238833	-0.0357299501373	-0.0233588854405	0.0547084785155	0.0164656259156	-0.0270950651899	0.087818 [...]
+449.F31Labi	0.203621087528	-0.0360730569689	0.0822308966273	-0.141137828778	0.213167281364	-0.0509913860408	0.0787943224253	0.0479049219027	0.0346636469931	0.14327381383	-0.0581445911138	0.0294032030377	0.0392322881813	0.00774678470727	-0.0838993410637	-0.0361927957313	-0.0230837109099	0.087046752478	-0.0199764510515	0.0481997778079	-0.00570806834706	-0.0753800310953	0.0232361832118	0.0527079503089	-0.00606358667725	0.0527492057696	-0.0199932891831	-0.0153129802944	0.0673296868305	-0.003 [...]
+449.F32Labi	0.226486293319	-0.0954777262222	0.105242149814	-0.0760463655651	0.25887228402	-0.0511965516153	0.0261961664845	0.103016493461	0.0453869441298	0.0303161767583	-0.0709882747724	0.0348570933939	-0.00759463137097	0.0217193366217	-0.0799530071425	-0.0927488077331	0.00129808887006	0.0588868054349	-0.0338641537828	0.0125548914377	-0.00578374554804	-0.0422002630592	0.0717655212833	0.0401605935148	0.00386017752211	0.0471130601051	0.0325737023761	-0.0235899896152	0.0958645175538	-0.015 [...]
+449.M34Plml	-0.144035410688	0.13213510948	-0.114924094129	0.0275165246931	0.0588182380236	-0.00796619395874	-0.0893306093685	0.0378295405657	-0.0470858567568	-0.0389637615895	-0.0137926383408	-0.0189554803521	0.0681467455721	-0.037150091598	-0.0249210946292	0.0112341878867	-0.0199317473852	0.0164749866742	0.0556329961061	-0.0156026673521	-0.0355462789853	-0.0600734640824	-0.0211251857656	0.0172017364682	-0.0232198995917	0.0268775720324	0.0165272933897	0.0404361022618	-0.0601527917644	0.0 [...]
+449.M53Knee	-0.148138182193	0.125797964746	-0.143359201507	0.0834712061019	0.0225497627275	0.00735756648545	-0.129129575332	-0.00402197605845	0.00500768949822	-0.0192628874073	0.0254828385981	-0.0242527263659	0.0474045973509	-0.0591626597839	-0.0357033412032	0.038874111026	0.00199100846201	-0.0678968689927	0.0964801891111	-0.00185520202909	-0.0143208202028	-0.107783900052	-0.0726089379138	0.0406289719938	-0.0138034167207	0.0153816407089	-0.028476550645	0.0189527256246	-0.057355466069	0.0 [...]
+449.M64Fotr	-0.113954225956	0.131178380248	-0.160299061485	0.157489263408	0.00316444819371	0.0918132968715	-0.0227533324551	0.0162688267887	0.117342736705	0.0318812990429	-0.104206542325	0.0198750030641	0.0896441210239	-0.0089715478207	-0.0496328417176	0.00225989812799	0.0232756804701	0.00390297113791	-0.0316928020791	0.045816229924	0.0330490214843	0.0189873572524	-0.00038111123001	0.00644025654323	-0.0202925037423	-0.00599344903775	0.0379620340941	-0.0705259966327	-0.0562300745483	0.024 [...]
+449.M14Fotr	0.0203179001585	0.189907298197	-0.0833671179378	-0.00371876852357	-0.0199424462283	0.125715040427	-0.107722176599	-0.0803497789384	0.0672423879526	-0.0386139722289	0.0359107081645	-0.0108740960572	0.0597681409242	0.0549190145868	0.0226265509669	-0.0122541677397	-0.145471650867	-0.0597720415191	-0.0321921651409	-0.0585738466781	0.0111505480677	0.000171065294258	0.0223076344629	0.00459379282934	0.0414538769456	-0.0855088500665	-0.0177974972033	-0.040090827835	0.0501092474576	0. [...]
+449.F24Plml	-0.0519619383091	0.17221732594	-0.0795515377638	0.0748092445835	-0.0313287095484	0.0922162753135	0.0880652996016	0.0053307140743	0.0161991213931	-0.0875495719949	-0.0786597402567	0.0535178238691	0.064887196987	0.0152641128181	-0.0210104831756	0.00165910963544	0.00338193200247	0.032158616745	0.0034032301536	0.0075516019749	0.0560328995545	0.0729846152596	-0.00798925968192	-0.00342935882177	-0.0598192918384	0.0112477896749	0.0376381641036	-0.056875672719	-0.0125609359817	0.0382 [...]
+449.M32Forr	-0.137891471818	0.186640266804	-0.0510524916988	0.0516838435446	0.0403361308198	0.0298295290907	0.0203028586855	0.0381369773854	0.0213340729762	0.0113989454438	0.0098587338049	-0.00797898751063	0.0125108938268	-0.0495147193444	0.0776812287511	-0.0784420150857	-0.0710093691072	0.029897029774	-0.0424413198563	-0.0554192317722	-0.00442613123853	-0.0155922542719	-0.0106194354328	0.0470725262981	-0.0826569168849	-0.0497941245795	0.0315109455802	0.0307590081548	-0.0204038562678	-0. [...]
+449.M12Ewxr	0.35090404994	-0.0795957637111	0.0306624364581	0.0795816241386	-0.0311533629123	0.0276068738765	-0.122666544683	0.214158574298	0.117505100257	-0.0975753135111	0.114792301635	0.0502999367673	0.00819830940084	0.0390668317429	0.0499224291135	0.0566350302365	0.0327901104198	0.0124636824168	-0.0253127415183	-0.0395048020112	-0.000478347573507	0.047976515799	0.0277768685997	-0.00929410236655	-0.0109093080739	-0.0741383579121	-0.049326982358	-0.0158841366957	0.0227980716713	-0.03336 [...]
+449.M32Plml	-0.137171926242	0.204635777088	-0.0651612607082	0.0947337917905	0.0031503995896	0.0315748924699	-0.00946694007505	-0.00196362488183	-0.035334372609	0.00173889949655	0.0861142461555	0.0463882548301	-0.0801257712028	-0.00560582586139	0.0137341344555	-0.00901082460321	-0.0975778170872	0.0282340642335	0.0447824667066	-0.0155578532627	-0.0490930101846	-0.0173015911035	-0.0708781630002	0.0349760854426	-0.040991292781	-0.0546820161585	0.000221844169603	0.0808014665382	0.003089352974 [...]
+449.F32Kner	-0.147134889557	0.206994009059	-0.111595025902	0.1387603019	0.0756549586315	0.0332870769913	-0.00349232069556	0.0041051717665	0.025955404544	0.071977917731	0.006123556068	-0.0014506387227	-0.0312494602989	-0.0802701249155	0.0493740157662	-0.00103061529421	0.0301516906373	-0.0414611796135	0.0025730657936	-0.0276687760451	0.0539891585279	0.0171578554351	0.0414764895935	0.0274926723935	-0.0311639345512	-0.01325202436	-0.00733304483706	0.0176332002652	0.116382363204	-0.0039296920 [...]
+449.M31Indl	-0.164388714199	0.0966188262244	0.119223577682	-0.00271543228354	-0.0293011571728	-0.0494345894384	-0.0719888682046	0.0150487784079	-0.129090617238	0.0471618349338	0.0315467496581	-0.00366799946662	0.0450732361703	0.0437057021435	-0.00613156447838	0.00414525619608	-0.0136242403656	0.0444887846501	-0.0126687910072	-0.0341353257142	-0.0327558843288	0.0187292247047	-0.0031400141138	-0.0169649103078	-0.0156329389588	-0.0217151096106	0.0278163912338	-0.0242654591601	0.004509479546 [...]
+449.M31Nose	0.234982429582	0.0225325139179	0.119113986781	-0.0711385735031	-0.0910300175508	0.043288698301	0.0226670467811	0.0172186331219	-0.0201029431004	0.0835222264047	0.091282767321	-0.0325908053586	-0.0327139787736	-0.0581604409109	-0.139275716109	0.0767843626295	-0.0899164976037	-0.0723409120279	-0.00445654123678	0.0345250630552	-0.0584953729999	0.0940587393593	0.0637326383248	-0.0138157405231	0.0128372862317	-0.0341574265648	0.059885617055	0.031204225708	0.021196194256	-0.0454620 [...]
+449.M32Indl	-0.133639305364	0.212197244345	-0.0515213595296	0.0495318093115	0.0156244608473	0.0415714236374	-0.00618427216483	0.0438631245086	-0.0467713407459	0.00428582369166	-0.0316453140116	0.0678042017418	-0.0319370809049	0.0328867675584	0.0122141997518	0.0323073991759	-0.0752460457071	0.0284333217326	-0.00668019668554	-0.018432091517	0.0133582494315	0.00182004803518	-0.0826272195638	0.0214802577594	-0.0259529048934	-0.0412627761986	-0.0675427639129	0.036357678908	0.0376803584901	0.0 [...]
+449.M21Ewxl	0.154867604423	-0.078810802657	0.0424270601761	-0.145319278262	-0.0520781470419	-0.0892625184086	0.0657833968608	0.127056027452	0.137336472238	0.033069354713	-0.102167393125	0.00750126042226	0.0443784351367	0.0333427451339	0.0320012435938	0.0789772102224	-0.0318918100248	-0.0422093753617	0.0964450483852	0.132920323008	0.0152574096635	-0.0399609414744	-0.0177505745738	-0.0631933020767	-0.0180215541545	-0.00981374308554	0.0454055504429	-0.011568135619	-0.0152377333178	0.0204605 [...]
+449.M22Tong	-0.152709968297	-0.183478915305	0.355751822077	-0.00456720523226	-0.0478460653698	0.0397636536339	0.0624637194859	-0.0791144839503	0.108684678399	0.0444367273075	-0.0408602096755	-0.00422653319319	-0.0109416248525	-0.0367782599968	0.0146494099673	0.0716809884919	-0.0411159159741	-0.00633116057879	0.00474104261428	0.0339725480598	-0.0290981017758	-0.0112431287824	0.0124187639816	0.0271615896883	0.0185236491691	-0.0117887655884	-0.0481250374939	-0.0285098022528	-0.0105615031932 [...]
+449.F31Forl	-0.130694218663	0.182714022567	-0.108110048594	0.0898555426664	-0.00207631445293	-0.0130214231768	0.0739974573411	-0.0446831002839	0.0538714713309	-0.0366812306819	0.0433359382344	-0.0273431876685	-0.0905923070544	-0.045584592895	0.0175221354171	-0.00325505916711	-0.00593344682925	-0.0328825788151	0.0747372297129	-0.0048860292102	-0.0396692470237	-0.0290127962647	0.000867936347503	-0.00364972099631	0.0302637614401	-0.0018104181662	0.00415084662826	0.0348736326834	0.0636958643 [...]
+449.F13Fcsw	-0.115569784146	-0.371318836413	-0.246444004866	-0.00524352664236	-0.0442869326027	0.0930811155457	0.000782358940078	-0.00665635648356	-0.0341407847152	0.0108705950911	-0.00783292281623	-0.0373908365987	-0.0324533624616	-0.00413028733382	0.0492526880268	0.0664284811643	-0.00549543918504	0.000856103891777	0.0233084051118	-0.0398357375971	-0.0584386123293	0.0298250717935	-0.0465332896904	0.0732228756113	0.142378603625	0.0028465835746	0.0310273883194	0.00953528187111	0.007943005 [...]
+449.M41Knel	-0.188794582182	0.152952302266	-0.0982760413334	0.0705440682606	0.0451986280529	-0.0535868588487	-0.0244671174418	0.01089894597	0.0383974759354	0.0326061580191	-0.000770511191165	-0.0816329986907	-0.0243396931983	0.0249101787225	0.0209723834792	-0.0174730776735	-0.0087465791238	0.038393973261	0.0453147064245	-0.0376059622284	-0.0201209480104	-0.0046468673981	-0.0142527951705	-0.0548979317699	0.00234934421635	-0.0276090864326	0.0244883783254	0.0567464614322	-0.0258461295369	-0 [...]
+449.F33Fcsw	-0.0836171021231	-0.40569500169	-0.285811105199	-0.0442565589378	-0.0158637856462	0.173984634948	0.0384686471528	0.00790623136191	-0.0774059615923	-0.00644040710936	0.0250354111268	0.0395553241713	-0.00889986732884	-0.00514670330479	0.0148687396571	-0.0190217715872	0.0240167566372	0.0305683112809	0.0459881259151	-0.00608966860855	-0.0257681985821	-0.035607096035	0.140379156324	-0.0175130937909	-0.104245783531	-0.00621331033065	-0.0664870313939	0.00645975361984	0.0060627040098 [...]
+449.F34Fcsw	-0.10140693362	-0.412865732128	-0.296404783173	-0.0380241315291	-0.0366945479946	0.168725131337	0.0648223099182	0.0143111495	-0.0969265768671	0.00232373053253	-0.0308898604201	0.0261143614355	-0.00199837768244	0.0175073424741	0.0200749488974	-0.0353206423918	0.040562574064	0.0229275788695	0.0518680408693	-0.00919443416187	-0.0382719335417	0.00698018414522	0.146799995319	-0.000368211741384	-0.106410155219	-0.0110501637173	-0.0654176117542	-0.00179046527951	-0.00210562022177	0. [...]
+449.M32Fcsp	-0.0829558850032	-0.39142439535	-0.240548451054	-0.0302566408416	-0.0126592594711	0.155384385298	0.0490856502085	0.0342228302581	-0.0301144181276	-0.0155709700179	-0.036995624513	0.0379634260259	0.0365202062688	0.0415484835159	-0.0029712591362	-0.0307387372062	0.0162228865519	-0.0262558171732	0.0195572022437	-0.0216781648205	-0.0103119504504	0.0119301186218	0.00547201805933	-0.0349252473778	-0.0194220342591	-0.0155357564931	0.00125075618692	-0.0156516273265	-0.08430933403	0.0 [...]
+449.F22Fcsp	-0.105595896897	-0.414608563232	-0.267888640696	-0.0223315661457	-0.0143337722049	0.183595168997	0.0409656061392	0.0271748812752	-0.0947582719594	0.00417600651241	-0.034849581218	0.0167591580096	0.0168955914134	0.0154723564621	0.0535475116766	0.0449703789412	0.0556458804416	0.0209423464664	0.0277550900791	0.0345412013803	-0.0994310034692	0.0599053722508	-0.0423473402125	0.115246323841	0.0782478438134	-0.0161888016408	0.0317072940581	-0.006389674385	0.00838580482387	-0.0159669 [...]
+449.F32Fcsp	-0.0674950723429	-0.4149676844	-0.326906635098	-0.0265288881434	-0.0181746042604	0.188062714972	0.0234414183405	0.00159214366624	-0.0928174935528	0.0340069014367	0.0180446630032	-0.00898959606256	-0.00473233828628	0.00642886691148	0.0434649853939	-0.00678906633909	0.0280764421078	0.0125578362315	0.0778378953227	0.00940640079874	-0.0270601578832	0.00550884955283	0.201610116381	0.0187849046495	-0.104242726797	-0.0139352755078	-0.0693566796827	0.00967230372765	-0.00186060060389	 [...]
+449.F31Fcsw	-0.0906115413288	-0.386901563504	-0.294052208107	-0.0413731744624	-0.0320523061155	0.149484457145	0.0301830703711	-0.0187527847632	-0.0813519239332	0.00421471038059	0.0137937856692	0.0206339723926	-0.0270401615852	-0.0288065750332	0.00485044976158	-0.0532890505179	0.0239771349864	0.0281331065823	0.0757665818372	0.0074574319834	-0.0422982703789	0.00851649705612	0.155461014917	0.0143778830221	-0.0906784335409	-0.00992140564782	-0.0747924784189	0.0301671720337	0.00581374272476	0 [...]
+449.M64Fcsw	-0.0556054237395	-0.4031245009	-0.271577094049	-0.0269876291175	0.0257917166935	0.165102884752	-0.00513704385389	0.0401850791191	-0.041521376027	0.0338803516583	0.0249135823693	-0.00843911334028	0.0221954058816	0.0212109973389	0.049614777584	0.0808580791379	0.00207004435205	-0.00463552620432	-0.000231820882586	0.0274479238124	-0.0110791205679	-0.00718988310745	-0.0293268469871	0.00959087897638	0.0745578772595	0.0292568076226	0.0178089293854	-0.046787299347	0.0467319480155	-0. [...]
+449.F31Fcsp	-0.102254864265	-0.395971233488	-0.269590314705	-0.0330167488839	-0.0301929392861	0.177264960575	0.0728401138452	0.0144856492653	-0.0949697039741	-0.0063825016865	-0.0413377903482	0.0341855281139	0.00590206394205	0.0240964916591	0.031187404038	-0.0358740869141	0.056227373503	0.0190256161535	0.0747576825835	0.0110296538247	-0.0482948490028	0.0133204915826	0.172264304708	0.0379229484794	-0.108168343744	-0.0215756913518	-0.0633676857788	0.00546695632857	-0.0134939378419	0.065333 [...]
+449.M44Fcsw	-0.084948337409	-0.348605712844	-0.290799040107	-0.0856831676276	-0.00765192363577	0.0459069012202	-0.0560585917353	-0.0279038033593	-0.0146330037518	-0.000244538551742	0.0481940418325	-0.0373533185475	-0.0691451372364	-0.0206132931924	0.00866182611071	0.0350165940184	-0.090150450962	0.0186678803491	-0.0479872770081	-0.0633327898207	0.111684429683	-0.0954249112723	-0.104401474846	-0.198751500996	-0.00190384657088	0.0916657665628	0.0303979453751	0.00215127456704	0.056815153344 [...]
+449.M41Fcsp	-0.0514228750693	-0.346069549421	-0.210179210647	-0.0346719328104	0.0391767398931	0.161946206022	0.0393531090219	0.0770425707118	-0.00538120295254	0.0138959002023	-0.0110581393853	-0.040521159619	0.00861319621623	0.0949424359139	0.0466477736647	0.067563465156	-0.0349738629723	-0.0350322872171	-0.111856796475	-0.00622447869757	0.115702716717	-0.113716567235	-0.0874632614258	-0.160567992253	-0.0240987278598	0.0789914779345	0.0774332256735	-0.0276826394625	0.0412823935967	-0.088 [...]
+449.F21Nstr	0.253557170953	0.10852543799	-0.0286614910377	-0.097354397497	-0.0245437484925	0.0547305963076	-0.00284537315282	-0.0615645616036	-0.0595122328716	0.0889759266069	-4.45689825446e-05	0.0348679155138	-0.0546256165156	-0.111525102471	-0.0408405437235	0.0358492714607	-0.0448464739949	-0.00491925426221	-0.117455435201	0.0653684459739	0.0673038384409	0.0111652893783	-0.00911666767131	0.0118351217058	0.0451027338363	-0.030425729866	0.0162438454938	-0.0017650203505	-0.0427482545499	0 [...]
+449.M44Fotl	0.155535252286	0.131535880232	-0.0428233327591	-0.0177671434295	0.0542578659899	0.0908083451242	-0.0360252553994	-0.0601666437235	0.06371589117	-0.118616891731	0.0292323892712	0.016185769729	0.0639834521372	0.0563501108258	0.0196124464445	-0.0824770884435	0.00890177324103	-0.029430519829	0.0534059470146	-0.158347108894	0.0857798840945	0.0400708489183	0.026969557033	-0.00436370071862	0.0360513469333	-0.00288893302128	0.122007441346	-0.0530034886296	0.0450847159871	0.0849150676 [...]
+449.F22Labi	-0.0490487386166	-0.297937174718	-0.135717586009	-0.0818681967424	0.208310502813	-0.0727936597773	-0.0644664326896	0.00109403924985	0.00302812942704	0.0609752882357	-0.0353144821359	-0.0645131587688	0.0513259896762	-0.0909082201699	0.14960456917	-0.0117253884864	-0.020418409303	0.0310653731238	0.0526889271776	0.106354123935	-0.089957678744	0.103751478541	-0.0816995483926	0.00236048995239	0.07847078104	0.0352273673231	0.0210699289351	0.0758526638872	0.0544406480567	0.059569975 [...]
+449.F21Labi	0.108081050899	-0.1654613243	-0.0206347102914	-0.0835146702874	0.342399780574	-0.0965937639027	-0.109926086137	0.030614354506	-0.0058899693901	0.102783131857	0.0259938672119	-0.006192995187	0.0666588787085	-0.0655772598266	0.120601718946	-0.0836693452579	-0.0489716159366	-0.0183725365923	-0.0181584951589	0.101107874163	-0.0328528174764	0.0929225359488	-0.0235266301107	-0.0656778781045	0.0229501501254	0.0472098409585	-0.0407623524799	0.0990278458935	0.0554970535507	0.058314748 [...]
+449.F21Ewxr	0.435446785825	-0.0519301024718	0.00974723680236	0.154725047262	-0.131812745446	-0.075962526558	0.0936993116023	0.0937281671269	-0.0161652736247	0.0300606258924	0.00444377847816	-0.0641277202316	0.10476728628	-0.0612731066427	-0.0107309206442	0.0339496169918	-0.080090226838	0.00125094781317	0.0610997288697	-0.00839944762529	0.0211074972696	0.0404910586795	0.0244677555063	-0.0141045695113	0.0300584850868	0.0166684124956	-0.056364640839	0.0398339877203	-0.0245264906149	-0.04447 [...]
+449.F21Kner	-0.0849770908494	0.11498826676	-0.028318852441	-0.00591676613953	0.0553582073047	-0.00675115906813	0.0562900214355	-0.011783708346	0.0228908761675	0.0618404377291	0.0283820404952	-0.0681072775087	-0.0218018606941	0.0110698076852	0.0327357721648	-0.0478722177521	0.0355875515555	0.0530063139185	-0.0596987856029	0.030488054186	-0.131216702341	0.000760522269275	-0.0100735407191	-0.0860321778581	0.0419858714541	-0.0159647290051	-0.0598621519937	-0.12408993541	0.0246415007304	0.035 [...]
+449.F22Urin	0.0917449872683	-0.216795243501	-0.0122509168781	-0.0502770441817	0.353974180313	-0.0928316950667	-0.0707020970794	0.0354737125817	0.0504936044236	0.0808602253842	0.0560201458557	0.0187709791813	0.112599891434	-0.0563320558203	0.12829608944	-0.0575323641422	-0.0420269506313	-0.0450371161016	-0.0209985299746	0.132623924921	-0.0225757359689	0.0640544541403	-0.0224118572817	-0.0684838238996	-0.000521664673558	0.0515304544041	0.00536510988735	0.115453076703	0.0491693785338	0.0659 [...]
+449.F21Urin	0.260031258773	-0.129364068343	0.0222863680147	0.0185908276062	0.392611231477	-0.0974174558258	-0.0254467594135	-0.0343967261846	0.024607916581	0.0478288275501	0.111759820814	0.0600199673735	-0.0428523625176	0.0312879752727	-0.0342307298072	0.0453575337152	0.0208357005196	0.0216230648061	-0.0762515723453	0.0889403776525	-0.0615403453597	0.091877911155	-0.0357954401835	-0.0385236595484	-0.00681741887186	0.0245188641294	-0.00826373338027	0.101603565832	0.029957055166	0.12837153 [...]
+449.M21Urin	-0.120369509849	-0.00424647870931	0.231636055689	-0.00991174860207	0.0614057459594	0.0165214533028	0.0629602453455	0.0073563717951	-0.0616462380998	-0.00910538524649	0.0626035668637	-0.0812840252672	0.104653533982	-0.0258746163796	-0.0155955197246	-0.0185950108835	0.0178659644305	-0.0258384639972	0.0101339038935	0.0135117818388	-0.0533060504931	0.0939927247735	-0.0223835536529	-0.0406430594205	0.014348131635	0.0317481465368	-0.013309484598	0.0232849220833	0.0752817982895	0.06 [...]
+449.M22Urin	0.113521570454	0.0236156098046	0.0663586088541	-0.106171692121	0.112853948544	-0.0146207279647	0.147658355944	-0.0587695212447	0.060155778769	0.0115636564569	-0.058457598765	-0.102764432112	-0.0197731199712	-0.0772188885537	-0.0382125475056	0.00854846863871	-0.0218244729378	0.0617688920452	0.174216556306	-0.0510304005838	0.0185185595335	0.0559601223051	-0.0573255682075	-0.00542348647667	0.0581635744313	0.0178362243997	-0.034247210529	-0.0611413466641	-0.0330201757956	0.079547 [...]
+449.M13Frhd	0.239033848454	0.101988083336	-0.0721816803133	-0.00264542061582	-0.00487827091921	0.0543671069858	-0.161082434656	-0.136197391795	-0.0175194868119	-0.22864905118	-0.123045261879	-0.0358297789427	-0.0724052016593	0.0772493720197	0.0217821725255	-0.0597625517136	-0.0456472162784	-0.0424108251961	-0.067862853581	0.0432135158392	-0.0214238304885	0.0408841018297	0.0613864920713	0.005970570428	0.0200272787111	0.019966440943	-0.0402731438369	0.0416739082157	-0.0302897271855	-0.0520 [...]
+449.M54Knee	-0.108490430139	0.0680695492652	-0.200197964932	-0.00815566599959	0.0135746807425	-0.0524627700291	-0.0870889684985	-0.0398292965577	0.07089648885	-0.062977866228	0.0139830716535	-0.0344563580511	0.0344285670537	-0.0952377222031	0.00764983513383	0.0172833105639	0.0120687447106	-0.0239767379346	0.0847831507765	0.0443102095693	0.00997180890144	-0.0863283968247	-0.0432855749277	-0.0393841891148	-0.0611139517432	-0.00559663683574	-0.0108029895708	0.0231458916838	-0.0788837099748	 [...]
+449.F33Tong	-0.173135930173	-0.162885506682	0.383795068375	0.00722349217628	-0.0513287935322	0.045051159388	0.0506585138642	-0.0702286260009	0.0745701962968	0.0383799891925	-0.0129946751779	0.00504162025199	0.00179361390488	-0.00880387339669	-0.00969206851798	0.0673537919384	-0.0408148468285	-0.0102969813872	0.0197894034028	0.0217962361413	0.0357587116682	0.00899491448057	-0.0265719272491	0.0250470919709	-0.0188955666355	0.0046459293892	-0.0581552530665	-0.0196950166871	0.0172320771777	- [...]
+449.M43Fotr	-0.00908945350839	0.199110632909	-0.112313237095	0.0370694753944	0.0497536350253	0.0750602094525	-0.0111403827691	-0.0429428376054	0.0628127064276	-0.0216649267509	-0.06090963986	-0.042756670572	0.107778795225	0.0430187422668	-0.0144829227657	-0.0797720725144	-0.0309874966671	-0.0158000390754	-0.00777899598985	-0.0475041816246	0.031415893109	0.0157372058439	0.00797102108294	-0.0228797780796	0.0340018202926	-0.0342150859374	0.0374906779739	-0.0351195798725	-0.00670975092148	0. [...]
+449.M14Knee	-0.0446287216921	-0.0322867963055	-0.147730827583	-0.116687750014	0.0574929890788	-0.0713058993094	-0.184549244709	-0.0648534212806	0.0779449997437	-0.0199821102461	-0.01805358608	-0.0918179362807	0.0905539986635	-0.0385676651853	0.0941325583736	-0.0404882917792	-0.171499018064	0.0313411210199	0.0927399706998	0.0461623073217	0.0207541430699	0.00260747041517	0.0324010485286	0.0705368116014	0.015964545051	0.100922227625	-0.0294546283518	-0.0528076391395	-0.0327628036954	-0.0133 [...]
+449.M42Pinr	0.164928321996	0.0914448169178	0.0809901392426	-0.114977378917	0.0113194182571	0.00061195516709	0.0939030373741	0.106710932816	-0.0364424331479	0.0100504153351	-0.0274158044645	-0.116725981313	0.0462702468565	0.0413870221592	-0.0816218980783	-0.0111267977148	-0.0663211887621	-0.0946464818202	0.057567423951	-0.0849126992904	-0.0451433499344	0.0599692306692	0.0332866064106	-0.0102717182545	-0.0265208716315	0.0413933965105	0.0737801495105	-0.0332122471059	-0.0107384879837	-0.004 [...]
+449.F32Fotr	-0.0892497755752	0.19044678175	-0.139474387372	0.0885770545027	0.0278976940442	0.0561260830515	0.0593496337527	-0.0116755896739	0.0918351820793	0.0289798691495	-0.0199569900751	0.0111445571731	-0.0195558996893	0.00325789315819	-0.0124892811235	-0.0805622337019	0.0153677518519	-0.01192663135	0.0190470960783	0.0147361762301	0.0083128091516	0.0201068421109	0.0137749210948	0.0139222039873	-0.0283427403075	0.0471539688039	0.00418315107599	-0.0672199454419	0.0277642147513	0.0199625 [...]
+449.M43Fcsw	-0.0992760238706	-0.400666696399	-0.316379101699	-0.0434478284065	-0.0312477663039	0.0651644548567	-0.0193100832454	-0.0307566489611	-0.00659656681353	0.0111472816232	0.0458297409717	-0.0584369239076	-0.0667515582168	0.00531406658773	-0.0241558980879	0.050338477006	-0.0879432314563	-0.0146042576869	-0.0691029847472	-0.0697758591741	0.114137492582	-0.094194595937	-0.0762645189893	-0.171867139092	-0.00706160846926	0.0611771620517	0.0446210584314	-0.0217888586505	0.0654785712679 [...]
+449.M33Frhd	0.0268867237064	0.0539092231089	0.0509232030516	-0.1359357207	0.0541511619745	-0.0131589573563	-0.0783947909337	-0.0181506687438	-0.082906775539	0.00210708685708	0.065772091383	-0.00845303972288	0.0616983089067	-0.12573448309	0.0440994566118	-0.0200350219868	-0.0799588809957	0.0746629843434	-0.0238224269974	0.0418522904063	-0.0640102434285	-0.00044206761422	-0.00917904052329	-0.0389661302578	-0.106586607844	-0.000447444141889	-0.00415738318217	-0.0727500572163	-0.028008627179 [...]
+449.M14Fotl	0.103440266937	0.137871629412	-0.0942080839573	-0.109203322198	0.0414240342049	0.0868124188758	-0.137117916394	-0.0542976075676	0.0825185859792	-0.0190574429012	0.0454383820514	-0.0736866391873	0.0686346072869	0.043353310669	0.0235876504631	-0.0105007893033	-0.104877284702	0.0236530902949	-0.0623180398785	0.0185735611918	-0.00851731662148	-0.0282288811914	-0.0357064320124	-0.00155545930864	0.00546594512081	-0.0888322396489	-0.0695526324301	-0.124798278476	0.0275223112252	0.07 [...]
+449.M43Knee	-0.145236785955	0.135096021175	-0.160092690366	0.0992556218893	0.0408315624544	-0.0104862447851	-0.041067272833	0.031186342532	0.0407378374651	0.055493124724	-0.0626187875789	-0.0702725759062	-0.0147944065145	0.0142078466765	0.00399952558988	-0.029196620717	-0.0138379212346	0.0446530430575	-0.0212934198815	-1.44001076188e-05	-0.0595168660781	-0.0310932912186	0.037671830592	-0.0745346858083	-0.0272427922316	0.0583645533314	-0.0129288432099	-0.0702765664528	-0.0299382511105	-0. [...]
+449.F12Labi	0.0863861492479	-0.054044395874	0.0861426437874	-0.161930985196	0.229865353653	-0.0686765433461	-0.0822308622418	0.012180627587	0.0530466845458	0.027317352275	-0.116014779298	-0.0143325575939	-0.0179369798289	-0.0910544091829	0.0959325053705	-0.0717158582114	0.0271543023592	0.0984531839221	0.0813344751388	-0.0903114045682	-0.0120893488129	-0.0207338259109	-0.0187600582315	0.0188857724328	0.0147366905826	0.0395018609271	-0.0135471186493	-0.0408854667654	-0.0159752707701	-0.045 [...]
+449.F22Nose	0.179022292028	0.103144917288	0.0105382426556	-0.10762985674	0.0306128872507	0.0210218128767	0.0919324883225	0.00941852930129	-0.0193622841435	0.0584775339168	-0.0215402566554	-0.038888343357	0.0104904268195	-0.0276955138636	-0.0709967961235	-0.0211193558414	-0.0682730723443	-0.122933158099	0.021720339005	-0.0521723763692	0.00972060700463	-0.0297048485692	0.137401848933	0.0105070869412	0.118283452258	-0.0361361916906	0.0373476545606	0.0907541681433	0.0492567094225	-0.04801064 [...]
+449.M12Frhd	-0.0477471358614	0.162164981626	0.0107726844246	-0.0787826705474	-0.0148805849408	0.0150135188541	-0.029459730868	-0.07466680899	0.0179428674956	-0.0713667288241	0.0649642077076	-0.0328923632545	-0.0995008602081	0.0209922616518	0.0567229404374	0.0576080173083	-0.0439187449008	0.000602813425826	0.0624752440207	-0.00138478435227	-0.0263977424719	-0.0694401509051	-0.0166364518906	0.00135371122277	-0.0143128510535	0.00507395723493	-0.0210689403521	-0.00573508230988	0.007800306561 [...]
+449.M41Nstl	0.0531963652542	-0.0351021466592	0.165505451964	-0.147766389543	0.101218550556	-0.0649123606155	-0.0725553967756	0.0581547353893	-0.080608784956	0.10927734056	-0.0787879463543	0.0772925570126	-0.0337906982395	-0.00610008361126	0.0732478604775	-0.00957663985872	0.0361776907809	-0.0459750834461	-0.0925880857826	-0.0986256577969	-0.0568417270268	-0.0439989840335	0.103277639756	0.0394446651404	-0.0203541568965	0.0649753875635	0.0398173104886	-0.0270352227365	-0.00826560946842	-0. [...]
+449.F32Navl	-0.0557085490622	0.188235019664	-0.0244569554079	0.00085677227399	0.0398045356449	0.0800337007513	0.172592318278	0.0778935532426	0.0364702846904	-0.0166999157926	0.0363090622058	-0.0126190124075	-0.027147452607	0.0100767053455	0.0263656269605	-0.0494613161989	-0.00676996772314	-0.0560075590938	-0.0469391366993	-0.0193027100504	0.0631049820151	-0.0270262669544	0.0028189631581	0.0463275725418	0.0323192573283	0.0605479395643	0.0262224472436	-0.000958209654428	0.0494436328769	0.0 [...]
+449.M14Nost	0.182687096847	0.0142786893397	-0.022377318875	-0.149429586221	0.0581169911948	0.0331135743261	-0.188103177641	0.0240988459589	0.0151115756674	0.00571512525598	-0.0348861634664	0.148325033533	-0.0315121855708	0.0795550336625	0.0501845456203	-0.149592068309	0.0125751090019	-0.0923918385183	0.0658963703936	0.0470753350013	-0.00921080746223	-0.0639207437553	0.0395913481108	-0.0910870920646	0.10009748651	-0.0393905288496	0.0262557443244	0.0222474797735	-0.0572035748287	-0.0172091 [...]
+449.M14Frhd	0.270406703986	0.0774770878139	-0.083225949768	0.0400543501585	-0.0444855397031	0.0700231581307	-0.189339175402	-0.101497775801	-0.0234726846106	-0.199844193272	-0.0752372638696	-0.078125576259	-0.0906893464892	0.0768536618968	0.0147906902899	-0.0329663089837	-0.0996811230004	-0.0410188328597	-0.111303719932	0.075314370142	0.0767036041015	0.0927344550729	0.0751104394527	0.0431050683959	0.0717674905443	0.0863307603386	-0.0181057089054	0.0970001390985	-0.0497884279381	0.0253015 [...]
+449.M12Fotl	0.00662931981942	0.19026044695	-0.121690486385	-0.0240537613994	0.0216037753273	0.0797815350572	-0.0895762989341	-0.0822859829923	0.0517736610119	-0.0772124754506	0.0225496305878	-0.00705118624349	0.0414405824422	0.00517280880361	-0.00193546880772	0.019775073964	-0.0995162940345	0.0166282362815	0.0244078536525	0.0526909344209	0.00589369414268	-0.00362743018831	-0.0469887286916	0.0120396561765	-0.0230333448967	-0.0565052236265	-0.0423125307953	-0.0903395656206	0.0343837046264	 [...]
+449.F14Fcsw	-0.0914100489655	-0.375611284076	-0.284060098904	-0.0294959975021	-0.00330398878676	0.100079364605	-0.0105178621774	0.0106065938937	-0.0725386044265	0.0305436713951	-0.010649644151	-0.00295759342768	-0.00731722506844	0.0205779587586	0.0405045914162	0.0312889793098	0.0387451990601	0.00424314723778	0.020362104478	0.00655958098774	-0.0417917262148	0.0356280029061	-0.0744435021543	0.0814173371239	0.135414657997	0.000164575472776	0.0281839475812	-0.00318188000335	-0.0149213498194	 [...]
+449.M32Nstr	-0.0772003226464	0.167653056303	0.0491554658534	-0.0385868372581	0.0367528071237	0.0269741682019	-0.0146642065369	0.0243201547106	-0.0975266581206	0.0583428131134	0.023365230001	0.086318311495	0.0168282075382	-0.081163911939	0.0353845259822	-0.0138624905888	-0.0531743235913	-0.0290476002585	-0.00884283405904	-0.0414258055991	0.0585141032418	0.0054407101783	-0.0260501612264	0.0432729501906	0.0344485090691	-0.0821811735576	-0.0259582774569	0.0122935766106	0.0735922115516	-0.023 [...]
+449.M33Tong	-0.193418813429	-0.211618108383	0.354898003896	0.0308476845292	0.0130937633004	0.0574733309033	-0.04777977298	-0.0475042208653	0.0293185572582	-0.0153761159429	-0.010502294365	-0.0217294275342	-0.0469767101068	-0.0245695910568	-0.0290392868167	-0.0429164643037	-0.0176690022787	-0.0411655406488	0.0242264258791	-0.0206037952722	-0.01579827284	0.00604342405288	-0.0229783428162	0.0297071714775	0.0067451521497	0.0111079116954	0.0235286442918	-0.0254823922359	-0.0182062203496	0.017 [...]
+449.M53Urin	-0.088894663191	0.0501145773475	0.109714019079	-0.0875973878029	0.0860565147623	-0.00428062644895	0.00578580824967	0.0494139247629	-0.0928390164819	-0.00494883128787	0.043975577823	-0.0489124727974	0.0868692071163	-0.0679245954607	-0.0192186217396	-0.0250671835232	0.040584823128	-0.0617079696742	0.0187422854551	-0.0579250559877	0.0677973416628	-0.0246435842788	-0.0559686273157	0.102425165788	-0.0349620415815	0.0846471886821	-0.0797469454086	0.0378320313433	0.0525028771998	0.0 [...]
+449.M23Tong	-0.168765606454	-0.233387030017	0.387892142854	0.0392763754585	-0.00220493450599	0.0386879126798	-0.000151389987805	-0.0390309552967	0.0941237293183	-0.0282295081388	-0.0412568616421	0.0270939255611	-0.0323574273802	-0.0264304240623	0.0172149878731	0.0294355850038	-0.00431212696872	-0.0329061223795	-0.0348364058023	-0.00409245273593	-0.0291050890042	-0.00099923312634	0.0196188968744	-0.00513625869311	-0.034651968731	-0.0157669836651	0.0272961539433	0.00589346176127	-0.0153069 [...]
+449.M43Tong	-0.187935117866	-0.227108410239	0.384560846128	0.0599718161687	0.0267355327221	0.0146788721248	0.00250220992567	-0.0529900830918	0.0594745261631	-0.0244329794584	-0.029462163289	-0.00152650655202	-0.0108647874293	-0.0258846854376	0.00994834772331	0.027716172352	0.00542178889623	-0.00719919896143	-0.0256688366668	-0.0253375713216	-0.0312726877891	0.00638631879332	0.0306585040159	-0.0172850641602	-0.0212352974228	0.00585629881614	0.0368414926098	0.00208819338206	-0.035787497620 [...]
+449.M64Tong	-0.193727572573	-0.212182032511	0.356475041881	0.0450194152881	-0.000602631212391	0.0637791535789	-0.0226369793128	-0.0531670318895	0.0532685831823	-0.0179576845801	-0.0127792446773	-0.00818927084757	-0.0553077529782	-0.029627400443	-0.0023413973576	-0.020561878562	-0.0391827936891	-0.0400774097426	0.0555234173657	-0.0189113576572	-0.0113527989544	0.0104446183696	-0.00952539293254	0.00171116694147	0.00541994117841	0.00971171479894	-0.0217682439947	-0.0465349764599	-0.00341355 [...]
+449.M13Tong	-0.192609621392	-0.200071067086	0.373008357476	0.0620335638407	0.00828074717856	0.0801180956197	-0.0280459240703	-0.0234019388537	0.0188311837587	-0.0297450343169	0.00657662664475	0.0157580750992	0.00122181989148	-0.0210774616727	-0.0297611588999	-0.0248241587388	-6.21751140211e-06	-0.0500579248381	0.0178371140098	-0.0190332518149	0.0418725365813	0.0100025362471	-0.078192294049	0.0350738779144	-0.0218773927907	0.0252571659201	-0.0291033671917	0.0113201297647	0.00850518712353	 [...]
+449.M63Tong	-0.199310200281	-0.230653303464	0.384720803974	0.0554119631668	-0.0103595635052	0.0657338284231	-0.0221123399634	-0.0449179121637	0.0383251687502	-0.0224371762318	-0.0282852906525	0.00355191288601	-0.030451184169	-0.0257115595664	0.016675806142	-0.00121894282334	-0.00402766635337	-0.0300813471974	0.0172636552159	0.000591580825752	-0.0159294567532	0.00296950005531	-0.000624717523024	0.011374051079	-0.0140832375056	-0.00271419215431	0.00342530372979	-0.0119308438911	-0.01529911 [...]
+449.F24Tong	-0.194919720017	-0.219512093767	0.374231175991	0.0700953540849	0.0285567281917	0.0284396357081	-0.0197250546884	-0.0497092625407	0.041723957524	-0.0275200464095	0.00295555921901	0.00242326043025	0.0121976241538	-0.0432864076717	-0.0322356987718	-0.0324125839212	0.0192834794911	-0.0573362118703	-0.0218066191214	-0.0406336315591	-0.00601428144371	-0.0170703860245	-0.0202720632569	0.0480453558682	-0.00281991948603	0.0424481073216	0.00194212327391	0.0239545996606	-0.0318020640069 [...]
+449.M12Tong	-0.1970930682	-0.195383809843	0.365178447115	0.0571413068756	-0.0296014704169	0.0555211033816	-0.068060170577	-0.0327024353036	0.0102151536363	-0.0161477349749	0.0138798834776	-0.0438083059628	-0.0188462153324	-0.0390375997489	-0.0274733137026	-0.0316996611636	-0.0086221374516	-0.0560148381599	0.0525005095175	0.00402791119314	0.00938396544457	0.0120001115258	-0.0404887251025	0.0313770936606	0.0312928914479	0.0276760973301	-0.0255917842076	-0.0447852481021	0.0124339160176	0.02 [...]
+449.M11Tong	-0.177137929468	-0.147633784766	0.359985849818	0.017666448631	-0.0170033171617	0.0325829305326	-0.0835332787008	-0.0208902483659	-0.0534708823118	-0.00186256758234	0.0159948360907	-0.0231453691411	-0.0405550370862	0.000354995107219	-0.0446612889649	-0.0423321587313	0.0322203429631	-0.0594124717787	0.0248089052164	0.00620512028595	0.0292288886843	0.0164415256117	-0.0500521586854	0.0358222913616	0.0238152958761	0.0285471627403	-0.0103935597496	-0.00227106624195	0.0158380390818	 [...]
+449.M21Tong	-0.145638619696	-0.240461123466	0.362551347147	0.0332410456447	0.00988416450152	0.0305688648879	0.00575760369387	-0.0498248182796	0.130905934208	-0.0192544353014	-0.0701956827577	0.0130141350704	-0.053982184026	0.0067392323212	0.0476567650122	0.0534122605293	-0.00490668509854	-0.0636842679541	0.00504313381712	0.0171974264152	-0.0382043037679	0.0049969963337	-0.00222813519074	0.00749143735439	0.011726289441	-0.0392648504452	-0.0561010463927	-0.0317932094701	-0.00675494548202	- [...]
+449.F31Tong	-0.166448027159	-0.159223074701	0.368581337214	0.015899507005	-0.0613941038208	0.0320265246762	0.0547338471963	-0.0498236797373	0.0810995997541	0.0449221056543	-0.0119861068968	0.0194669012376	0.0148486516598	-0.0155036386385	-0.000716247021857	0.0500568058142	-0.0351221346948	0.00848889492336	0.00503594473207	-0.00250919321305	0.0660341695653	0.0131603839221	-0.0135711848321	0.0543275133231	-0.0196126896397	0.0073777934693	-0.039089237097	0.021541724588	-0.0202939073893	-0.0 [...]
+449.F24Fotr	0.332407699679	0.0347374976335	-0.0349760773927	0.0931194193513	-0.172775080173	0.06905925966	0.00640326912592	-0.145226676528	0.0705121796486	0.0584344832609	-0.015480226108	-0.0881032425368	0.124200799034	-0.0135361549739	0.0395639695035	-0.0273097297524	0.0436806253226	0.132220115008	-0.0963509801876	-0.0263786053886	0.0119594890855	-0.0653930577388	-0.0221820508624	0.0236892834165	0.0130350913883	0.0551616946767	-0.0247715352605	0.0151397145026	0.0146137259216	0.045383302 [...]
+449.F12Fotr	0.230384576549	0.0763357803578	-0.0728458478674	0.0356952504776	-0.0655218232675	0.0787941475588	-0.012253847091	-0.121367966963	0.150074338962	0.155350748919	0.0920670720654	-0.0659996748969	-0.0479773340226	0.143876368777	0.0710153382762	-0.0962427740141	0.00587937701498	0.0762876077298	-0.0792059087821	0.0349356357697	0.0279849016274	0.0284414916535	0.0123741901289	0.0347779223745	0.0208353173257	0.143201144071	0.0130230584723	0.0414031577551	-0.0924583785353	-0.0088404126 [...]
+449.M42Ewxr	0.20883913173	-0.0439478149339	0.0679183336811	-0.0422651112588	-0.0915192500873	0.0177443836034	0.0732524724329	0.242298752778	0.117113952441	0.0405972068343	-0.0316617853222	-0.0463977358251	0.121994548967	0.0889061487216	0.031055198647	0.0466397154732	-0.0599248416198	-0.138417516168	0.0300686995702	-0.025771151441	-0.043074324754	-0.032009268881	0.0407181160061	-0.0126969343496	-0.0171427895806	-0.00389831866595	-0.0334878316893	0.041979964491	-0.0310488335767	0.002510792 [...]
+449.M32Fcsw	-0.0869750476649	-0.427652625135	-0.320590786586	-0.0385250000057	-0.0151936906134	0.118082175149	0.000961662903545	0.0194060126124	-0.0476206064868	0.0238124980107	-0.00595415729753	-0.01609753265	0.0119304574437	0.0075426203937	-0.0397885891596	-0.0286336565455	-0.0264313819758	0.0095559942659	0.00992412929133	-0.038756708037	0.0243212706122	-0.00486919558829	0.0570659768623	-0.0452283306431	-0.0602404577526	-0.0192128079848	-0.0322478049475	0.00380361863409	-0.030414714311 [...]
+449.M22Aptr	0.0102312464373	0.0619881659054	-0.0354717767393	-0.141383961574	0.0212055589183	-0.021761233406	0.107415596232	-0.0374785203592	0.0562103269182	-0.00668435201053	-0.0295321947123	-0.0335670669493	-0.0202092347049	-0.0574070040843	0.153447710414	-0.0396010204194	0.0671003008739	-0.0620736938143	0.0506512078917	0.0258930244732	0.0560145956671	-0.0138018572767	0.025364361597	0.0140565168899	-0.0266232739991	-0.0139381639907	0.0919325390703	-0.0403720852837	-0.0792746839662	0.08 [...]
+449.M14Plml	0.0392195824523	0.152441008409	-0.0720720247498	-0.0444230400793	0.00985220068821	0.106206592251	-0.0938932070437	-0.0701215914693	0.046630547066	-0.185232860946	0.0233508801692	-0.0040202726164	0.071531475528	-0.00538927416152	0.000351021288024	0.0188220195924	-0.0999095064402	0.0357870548893	-0.050810869059	0.0885017483921	-0.0269836614142	-0.0318183236323	0.0495051675016	0.0210103483713	-0.0315760211547	0.0679027102997	-0.0320161492772	0.00634329696278	-0.00349561566081	-0 [...]
+449.M24Frhd	0.111759402183	0.210620712923	-0.0316660562859	-0.0946623508443	-0.0231692298709	0.0262785638287	0.0298046753395	-0.104857337407	-0.0666755084178	-0.108923579694	0.0297665494784	0.117293858325	0.015467788891	-0.021791192739	-0.0323833119324	0.0601944761601	0.00949272612087	0.0383569935702	0.0643532322321	-0.0247317630763	0.00373193781344	0.0687787024682	-0.0252173392654	-0.00504371066187	-0.0167228485302	0.033061915022	0.00170394434819	-0.0479795282688	0.0109953640235	0.01190 [...]
+449.M34Ewax	0.375028622479	-0.0911411046868	0.0426795400159	0.104155367943	-0.04257104224	-0.0735453536379	-0.0846501259262	0.0504936951296	-0.0572805833665	-0.0399659047954	-0.116308551544	-0.0141957487559	-0.12413668716	-0.00899755833735	-0.0240358672382	-0.0775911599701	-0.016516940957	-0.0272467065603	0.0203142231743	0.0375467508948	-0.044191457878	-0.0892683886737	0.00958220423539	0.00252293583705	-0.0354566293887	0.00718466123982	0.10977949374	-0.0105726552137	0.081481153791	0.0484 [...]
+449.F32Frhd	-0.0362024499043	0.149394713584	0.0321896859954	0.0667256746391	-0.0322957851966	0.0872059025893	0.139775052279	-0.0454236921492	0.0239590007813	0.0416509939088	0.131266527499	-0.0159083195243	-0.0828494769923	-0.0254028249548	-0.0126487252818	-0.0892085843205	-0.0622953272616	-0.0521920695823	0.0127581454345	-0.0189573559808	-0.028540745655	0.0394499430837	0.0276210772667	-0.0293204566646	0.0581906627324	-0.0608488180141	-0.0548845890106	-0.0170697578505	0.115481557869	-0.04 [...]
+449.F12Nstr	0.0324498740827	0.113911332602	0.101864622558	-0.0890370693519	-0.103608629907	0.023917813018	0.113076213137	0.00557177552707	-0.0373214753603	-0.00900333459113	-0.0450203412197	0.0871962173135	0.0486664449726	0.0411547738175	0.00446208562695	0.0127719455115	0.0195393533758	0.0143409204455	0.0506524771874	-0.0706485871526	0.000452399006639	0.00448401589372	0.0265439121306	-0.0680556136417	0.0377518128205	0.0291615002369	0.0366946078286	-0.0461333763559	-0.00775053273078	0.092 [...]
+449.F14Tong	-0.12965357263	-0.206904585759	0.35425998021	0.0228956321731	-7.84066525324e-05	0.0316731526731	0.0127484988376	-0.0280556837688	0.0919184873007	-0.0306630429612	-0.0610354126477	0.0525052393814	-0.0328277323284	0.00599357231573	0.0652962645776	0.0529086080266	-0.0340341382136	0.0318621074954	-0.0363702485533	-0.0206788517502	-0.00774760623555	-0.00826187705535	0.0353135387984	-0.0293677079071	-0.0427434968762	0.011703908141	-0.0129497268635	0.0455684383063	-0.0320304101382	- [...]
+449.M64Nost	0.216813470763	0.0497755195894	0.0416051861191	-0.144589593079	-0.0332084523358	0.0318893306623	0.0274638585609	-0.00852527839359	-0.0620718096221	0.11820975894	-0.0516114595185	0.163340047307	-0.0449985568219	-0.0646237173976	-0.0603685058515	-0.0809324819675	-0.0499153748352	0.0238989449967	0.089589952993	0.00749676267424	0.0463845266152	-0.00308580515442	0.0228936077999	-0.0467611348195	0.0519665332864	-0.015857424026	0.00196869996746	0.00616710682324	0.00668932976988	-0.0 [...]
+449.M44Tong	-0.197811924518	-0.210450517796	0.386685668342	0.0686829863213	0.0288258812476	0.0250817435378	0.00870219944244	-0.0443889458524	0.0315602956788	-0.0205974198186	-0.00224914742189	0.00758189637432	-0.0123696437759	-0.00951828120443	-0.00281613412096	0.00936374158665	0.00208600449754	-0.0187134759118	0.00996475394479	-0.0283898753726	0.0096624596023	0.0303887199516	0.000209461883228	0.00134217377608	-0.0277333901995	0.0145222069925	0.0246681288132	-0.0180342014127	-0.004745821 [...]
+449.F22Aptr	0.229554547733	0.155558800481	-0.0354256138055	-0.173324953975	-0.00542180905504	0.0631450575246	-0.040028381285	-0.0776176702842	0.0259033755349	-0.0402969588293	0.0594527315036	-0.042323835199	-0.00224827147026	0.0038287160041	0.000668947892329	0.0681264158322	0.0942124684455	-0.0530119466132	-0.0296608540538	0.0485801901447	-0.0217678357921	-0.0581192313008	0.00909116941975	0.00543497206155	-0.019426184247	-0.103594506708	-0.0484298141325	-0.0501060050125	-0.0127008797606	 [...]
+449.M54Nost	0.183904327665	0.114519675592	0.0139482260766	-0.14678814832	-0.0341293527373	0.0539759921055	-0.0352703994459	-0.0804014966712	-0.0327892547729	-0.00913260734821	0.0140573234118	0.162040691536	0.00916678664364	-0.0221927179286	-0.00677270995121	0.00882041429759	0.0466519279133	0.053813511108	0.0294500299146	0.032062564648	-0.0170439903513	-0.0497517165583	-0.0293756762445	-0.0347011316528	0.0141395447795	-0.0303141457323	-0.00577794087449	-0.0489892694857	-0.0553392754571	0. [...]
+449.M63Nost	0.136551414947	0.0715769392027	0.0837996656523	-0.169439818675	0.0511002460563	0.00162332394175	0.0272546960034	0.0310018898746	-0.0738129135957	0.0648235548055	0.0239599271116	0.110575806241	-0.00975059844454	-0.0399965321823	-0.0493517315951	-0.0259946029015	-0.00824438613885	0.0850302660134	0.0622641594555	0.0328522380041	0.00681572600489	-0.0455906388009	0.000989461844498	-0.0320930967758	0.032614135406	0.0227230628729	-0.0273078213284	-0.0318652887413	-0.0159453289573	-0 [...]
+449.M63Ewax	0.383298262405	0.00481332978012	0.000158426924161	-0.0266092782001	-0.0767577641785	-0.0306598842703	-0.134805372417	-0.0121153631672	-0.128880685422	0.00560699923456	-0.0178803192298	-0.00452501364359	-0.163818666669	-0.065646084877	-0.0459719066738	0.043563062216	0.0279123610391	-0.0532427324994	-0.0538899830439	-0.0319270711114	0.0432787496954	0.085649761758	0.0282223559109	-0.00311211741677	0.0426740697655	0.0370913673138	0.0569752136929	0.0507020337363	-0.027685561999	0. [...]
+449.M53Nost	0.281634583248	0.08166949853	-0.0110467802991	-0.133310312581	-0.0979703894417	-0.0255360574409	-0.0341399248318	-0.138193526785	-0.0720674246389	0.0479699191762	-0.137793253244	0.0824003054018	-0.0490904954977	0.0144832337271	-0.0142743970814	-0.0276821504917	0.0289411849587	-0.0297351279227	0.0720213305721	0.0315581585797	-0.0555297599458	-0.0678181482525	-0.0326409829192	-0.054613701004	-0.0189814845658	0.0106269211381	0.0279997838503	0.027042834542	-0.00326685744109	0.009 [...]
+449.M64Ewax	0.350021537503	0.0211572074588	0.0392028976471	-0.152113645582	-0.0261651481032	0.00914745614499	-0.0657589017489	0.0161242316927	0.0152350263649	0.125849217352	0.0473447359929	0.0867571092403	-0.0514491252608	-0.0179515804611	-0.0593660480696	0.109557627129	0.052802446967	0.0420728400857	-0.0509961202599	0.0521620156122	-0.0286627002525	-0.0250603286372	-0.0182710352625	0.0344235122257	-0.00969463319975	0.0288328876932	0.0256507086797	-0.00977887737172	-0.0489878605711	0.008 [...]
+449.M34Nost	-0.00435673577054	0.161254647502	0.0187278038784	-0.113603017284	0.0153675890159	0.0292525804158	-0.00701139034871	0.00748804374607	-0.0386894403594	0.0127669157225	-0.0785940001409	0.113344203799	0.0463267313044	-0.0199765300771	0.0637106872203	-0.022520769171	0.0143148092131	0.0168854342742	-0.0524892534285	-0.00821418579064	0.0405552418592	0.0510381373721	-0.0478552700847	0.0104509786929	-0.0443104101542	0.0608217577543	0.00351678049065	-0.0820736327235	-0.0338215128494	-0 [...]
+449.M13Nost	0.235279513977	0.0451873383521	-0.0426909844157	-0.199740269129	0.0130745016707	0.0158321299489	-0.0779042939437	0.0224491317726	0.037763447042	0.147064492167	-0.00234595358825	0.069006748638	0.0280222298688	0.0851638582112	0.0318642408519	-0.0390934457041	0.0541606862605	-0.0883565074823	0.0748321393459	0.0677468314173	0.0878825112228	-0.0684493916327	0.0250303492947	-0.0513409948093	0.0665797181725	-0.0426151981744	-0.0516312335557	-0.0215711951704	0.00154087985622	0.031905 [...]
+449.F13Nost	0.278425459033	0.0697438343387	0.0082018412125	-0.106053252871	-0.0603397509708	0.0399500820029	-0.0599506026071	-0.0739645109592	-0.0356937820498	0.184764058775	0.00921259199722	0.0483230868405	0.031196160373	-0.11214987815	0.0935127151972	0.0286949524207	0.0204222853441	-0.023065979653	-0.116338172072	-0.0283447718209	0.0852340244409	0.0728481888499	0.0126917027387	-0.00969241070511	0.0362202608379	-0.00833118329165	-0.02075327618	-0.0408592835236	-0.0801439587058	0.0621042 [...]
+449.M34Frhd	0.21948368473	0.0505644603505	0.0275174134016	-0.0394380626989	0.0407322187133	-0.0231472050401	-0.119271243478	-0.112611525557	-0.150740236389	-0.0235207163366	-0.0208953258132	-0.00275062418036	-0.0503641807569	-0.143280068972	0.0823861377635	-0.0559583460603	0.00145740585908	-0.0360205176056	-0.0692418457099	-0.0868556381763	-0.0158137890961	0.0837413143509	-0.0247499900934	-0.010832522727	-0.0413956547556	0.0342188067606	0.0587788161177	-0.0213610927848	-0.0346250892266	- [...]
+449.M53Ewax	0.420784882511	-0.0489387268218	0.0238013945021	0.0325261664158	-0.0471042564395	-0.0694811261773	-0.0921742435459	-0.0169203167436	-0.113454926217	0.0198917469009	-0.0800817558591	-0.0145251091475	-0.181171490405	-0.0897483466191	-0.0630388950774	0.0117399862015	0.0657993752572	-0.0118961547358	-0.0420403664907	0.00753911062796	-0.0226490324448	-0.0402269964774	-0.0224269194762	0.0221969173228	-0.0232552732741	-0.0160633563272	0.0605604933318	-0.0155563618765	0.0092159814424 [...]
+449.M54Frhd	0.102970354419	0.108396285761	0.0130504751238	-0.105155101114	0.00141848850644	0.0870815876245	0.0744776543774	0.0257000242342	-0.00114842721625	-0.0455154952935	0.022584621294	0.0126290469084	0.0286426628495	-0.118002870003	-0.0327919986785	-0.0166784486002	0.0514650113571	-0.010991105236	0.0153540463067	0.082484349465	0.0458967085231	-0.0119222637537	0.0336678112743	-0.0658571443378	0.00950544976278	-0.102210873287	0.0249857808158	-0.0344779386649	0.0117195857044	-0.0555251 [...]
+449.F22Nstl	0.185705668558	0.0699299223437	0.0978736126193	-0.20748318276	0.0249349777014	-0.00550136351208	0.0190157780638	0.039488927373	-0.0720855924784	0.126037603888	-0.12993098378	-0.0173506331236	0.0222820249019	-0.0187958856424	-0.00376171216231	-0.0579183967101	-0.0596423959144	-0.0234014313471	0.0467238280438	-0.0091346655033	0.0777093415691	0.104400151035	-0.0132718823922	0.0368045792937	-0.106211641192	0.0147314914555	-0.00274767983347	-0.0188276393797	0.0406232061573	-0.0510 [...]
+449.F21Aptl	0.17371941901	0.177146080632	-0.0677396305735	-0.0412663121249	-0.0930373746021	0.0485095669719	0.0524609449488	-0.166007300769	-0.0392832192292	-0.0201985908981	-0.000777051968069	-0.0325236738189	-0.1047018825	-0.0612868984591	0.0574306972831	-0.0458520422474	0.0915303463463	0.0196968975238	-0.0594716513481	0.054796836632	-0.0328762212281	-0.036135064017	-0.0668205952674	-0.0327714257421	-0.00600494124645	-0.00234092140062	-0.0534151069746	-0.0517422496357	-0.0601875479534	 [...]
+449.F22Nstr	0.0355963773284	0.0484088348876	0.138072320087	-0.188266184014	0.0633691471646	-0.0616671161859	0.0366371889089	0.033192440371	-0.0186005972718	0.0252296723088	-0.0814920869192	-0.0504580303525	0.017269646362	-0.0363893015586	0.0466644253353	0.0830176180137	0.0255105060363	0.00725211114969	0.00684984316428	0.00151673147974	0.0964716074906	0.0782983638772	0.00725451324595	0.00308247867316	-0.0524412558667	-0.0497840831247	-0.0155751431861	-0.0391704774298	-0.012955974738	-0.07 [...]
+449.M31Aptr	0.183583509122	0.0407801836231	-0.0555400457579	-0.213480436737	0.00484238893102	0.057895137495	-0.0150186186778	-0.00858626163644	0.0527320978115	0.0577104997091	0.0585556440221	0.0143611443406	0.0446337141951	-0.0207014665406	0.0316215574771	0.0297067330079	0.16489871922	-0.106949065086	0.0261134482156	0.0416897632593	0.0147755513544	-0.115250179364	-0.00911267176099	-0.0307913909504	0.0491330682031	-0.00562796728724	-0.0138485098533	-0.0539955174449	-0.0774871322388	0.0275 [...]
+449.M12Nstr	0.268196569895	0.107118130909	-0.0292912622276	-0.145935441024	-0.0514688202742	-0.023088255743	-0.0445018571058	-0.109829885618	-0.0720149423216	0.0444780929571	-0.163855359637	0.0169770588778	-0.0430981902679	0.0480889473011	-0.0177053474109	-0.0508430654427	-0.00529864764913	-0.021456695865	0.0611252218691	0.0422895391889	-0.0215058624631	-0.0631514883659	0.00744932113585	-0.0080129785762	0.0151494264175	-0.0186324407215	-0.0479620097573	0.0521907543838	0.0512214707708	-0. [...]
+449.M31Nstr	0.0420572275932	0.0756802030539	0.0635817254441	-0.115251276325	0.0858576169531	0.00485182830478	-0.0363982555335	0.0427257897755	-0.0678535425086	0.137784713196	0.0483319168164	0.0912983083018	0.0624985362768	-0.113742935488	-0.00838767109511	-0.138607876093	-0.0324402225555	-0.00802384557826	0.0423295740999	-0.00335563400961	0.0467457836521	-0.020024543638	-0.0415692342784	0.0279085955211	0.0215613805922	0.0168704574446	0.0157662035744	0.0306810589533	-0.0273125483002	-0.11 [...]
+449.M32Aptr	0.38972631691	0.0843187344732	-0.021083699178	-0.0820716955097	-0.103673515089	-0.0277955386341	-0.039679603995	-0.147809150425	-0.039789537719	0.0961609394541	-0.0713775297619	-0.0587021621749	-0.0497283783183	0.00837412233774	-0.0336346048322	0.00977373341105	0.0677876217455	-0.0292011134026	-0.0223819190127	0.0216362182289	-0.0280046279891	-0.0605925515203	-0.0697831072059	0.0235992859249	-0.00601512325553	-0.0445279703045	-0.0525301077724	0.0185106601297	0.0154177149835	0 [...]
+449.M12Nose	0.310751684063	0.00851646863849	0.0179470693563	-0.124423056058	0.0704147173699	-0.000827569424774	-0.191294180865	0.00136630221354	0.0192134102004	0.00168927995461	0.0299616044828	0.103658439964	-0.101697003938	0.0843287490439	0.00286713035177	0.0528518146764	0.103382764634	-0.0292849752792	-0.0424600499796	0.0137889139281	-0.0524895189629	0.00897140088749	-0.0129979615865	0.00972805839444	-0.0266874282952	0.0189223726226	0.0239713337096	0.0361130931933	-0.00344606051518	0.0 [...]
+449.F11Nstr	0.133100373571	0.0857643134735	0.023541609019	-0.0830533144321	-0.0102292266445	0.0324049548098	0.0229529334626	-0.0452383899754	-0.0206806705233	0.0946221560146	0.0811083681208	0.144723432911	-0.0127588491735	-0.0619173110843	-0.012730049662	0.0403327138685	0.0401461495691	0.0057096032675	0.00598586607313	-0.0578894119676	-0.125356371649	0.00196148216312	0.0336417784208	-0.0556148706641	0.140499363906	0.0775722723099	0.00930957224082	-0.00974901816366	-0.0970852187928	-0.002 [...]
+449.F11Navl	0.213687501192	0.0152538957866	0.0308045232609	-0.138997608471	0.215080076047	-0.00365205328391	-0.164827374695	-0.0102493764426	0.0468674138289	-0.0086977062423	0.0304070291484	-0.0415033788596	0.000983240099605	-0.0104030128596	0.0419692961337	0.00747514586365	0.0658350320096	0.0233853398316	-0.0354105837489	-0.141330149233	0.00688944173587	0.0648856317558	0.0304495317214	0.0304697680458	-0.0700166845191	-0.0197795915181	0.00759429637844	-0.017049070696	0.00694094324579	-0. [...]
+449.F21Nose	0.25453137031	0.0255788753689	0.0974053094387	-0.125237343991	-0.0617318689236	-0.0340850602907	0.0353719028963	-0.0364581674774	-0.104573559427	0.0892174657049	-0.224373259256	0.0306378053236	-0.0130186771083	-0.039536997555	0.0425169140473	-0.0778116844876	-0.0166216418829	-0.0717587902085	-0.0342010940488	0.0578744666678	0.00769519720367	0.0271183133423	-0.0846133231526	-0.00582416271483	-0.0594229951176	-0.00394593859949	-0.0390710968771	0.0261894908855	-0.022049890042	-0 [...]
+449.M31Frhd	0.204673808742	-0.0232765510249	0.141175608494	-0.130474746594	-0.00725374519244	0.0071329717139	0.0422737717531	0.151460222448	0.0536875239523	0.0617529684238	-0.0642435652289	-0.0053338963788	0.0351176205632	0.0689911549044	-0.0675585518018	0.0163657370884	-0.00464872958226	0.0172371836311	-0.0399719734369	0.107002750765	-0.0662815509923	-0.031287590275	-0.100780228428	0.0373578247074	-0.100157162673	-0.0121053018568	0.00603360785729	-0.033669999523	-0.0310800853558	-0.0233 [...]
+449.F32Aptr	-0.0830899593611	0.141689710487	0.0214186507353	-0.0327280761757	0.0218843163445	-0.0104299675569	0.149239434508	0.0491190914031	-0.0449214300607	-0.00291462542201	0.03930347287	0.0157036512275	-0.0924176638942	0.0489723778821	0.0273727136476	-0.029587258739	0.0324627910858	0.0197569858533	-0.0177386434631	0.0224881409437	-0.00396683048633	-0.0450538162782	-0.0070535342829	0.0082472934262	0.0267845079489	0.0882723394291	-0.0832663471505	0.0349333739388	0.0352708847205	0.00733 [...]
+449.M42Aptl	0.212202743091	0.139241830884	-0.056184409682	-0.0880619369704	0.0403591553473	0.0679834195672	-0.159812261938	-0.0740874193218	0.00327491910905	-0.0826178688569	0.0653570623165	-0.101939766411	-0.0500246130471	0.128232866564	0.00976595820735	0.012471845237	0.0719839500126	-0.0491703902919	0.0528954394622	-0.139774694083	0.0490987980109	0.128951865408	-0.0292806953946	0.00777869613202	-0.0695081134006	-0.0361608089771	-0.0331414440957	-0.0676507287868	0.0381636866371	-0.01984 [...]
+449.M42Aptr	0.300828640896	0.118839297736	-0.0368178916938	-0.116615046995	-0.0307139409594	0.0587065239719	-0.146735050174	-0.106058654921	0.0538525075132	0.0495768625517	0.0669720537258	-0.0828222262252	-0.00598227633034	0.175027613356	-0.0221626809452	0.0220433913507	0.00174752001655	-0.0246552877208	0.0674750564498	-0.0533358601023	0.00829460807776	0.118587766637	-0.0587819262318	0.0169840516105	-0.0736148842742	-0.0566356776039	-0.0826080216767	-0.0336254212864	0.00882870651051	-0.0 [...]
+449.M41Aptl	0.305257104419	0.0112632100858	0.00632067908144	-0.116862985142	0.0801215252072	0.0159511920412	-0.187929706045	0.0091730089093	0.0402582585748	0.0661972309895	-0.0216117401937	-0.00171520429662	-0.0670373558118	0.178968716666	-0.00971617792561	-0.104839277684	0.043507699497	-0.0539011012416	0.143849513173	-0.0873298207096	0.0744450071766	0.0638846972663	0.00611081448529	-0.000988133787151	-0.0194336855931	-0.0173571690386	0.0132112560322	-0.0150559554925	0.0506407402705	-0.0 [...]
+449.M41Aptr	0.243641021775	0.097635136105	-0.0423082205037	-0.13306959299	-0.00817835712366	0.0435524071939	-0.04953888628	-0.000694868170615	0.0764181156274	0.0821821341278	0.149467094467	-0.0816746272306	-0.0965591475713	0.138000156899	0.0315450915542	-0.0059215861676	-0.00928056233836	-0.0630595573712	0.0704165076741	0.0260651507367	0.0632925892507	0.092347701988	-0.0529849942908	0.0367146952275	-0.105405753229	0.0177865121253	-0.0170079288752	0.0074348371819	-0.0422823888966	0.002021 [...]
+449.M32Ewxr	0.278433664299	-0.15005690203	0.0801045167844	0.0819481373453	0.0344942590713	0.00730086481477	-0.0914155632371	0.22733564941	0.0950518712984	-0.0393229867235	0.100670526461	0.0696910883408	-0.0241912776789	0.0124283619666	-0.031042579219	0.0164877602842	0.00288983967255	0.0636096122932	-0.0556481595385	0.0760800967192	-0.0364888255993	-0.0526285791876	-0.042868588042	0.0737855917059	-0.061245813547	-0.0176210445702	0.0765366356398	-0.00343598365725	0.0207945363248	0.00051196 [...]
+449.F21Ewxl	0.396543094164	-0.12286178721	0.0255373948193	0.161363090014	-0.0692516946624	-0.00440558786197	-0.104218584948	0.237250412401	0.0855569065624	-0.0486639997194	0.123779377204	0.0474556350139	-0.0154420285066	0.010261866855	0.0624309657545	0.0259724846231	0.00837907402597	0.0144268697019	-0.0127065570727	-0.00181698328407	0.0657722966711	0.0435829487638	0.0469941649336	7.94197452292e-05	0.0265266154137	-0.011561671721	-0.029295377457	-0.0197208094484	-0.0421528466012	0.0331591 [...]
+449.M43Ewax	0.456632293129	-0.141719674321	0.00043898222997	0.296058580067	-0.146118618911	-0.113368284944	-0.0886179075239	0.178367208903	-0.0368385667305	-0.0479140150066	0.00626769207285	-0.0201443416028	-0.0298205947136	-0.0171921391687	0.0938429959501	-0.0304459803267	-0.00518153217278	0.00968334657601	0.0224861340347	-0.0317191311246	0.0496141450858	0.00503172896513	-0.00128543839375	0.00130119444529	0.0268364791616	-0.00366280301226	-0.0446043284009	-0.0248393289805	-0.00569656825 [...]
+449.F11Urin	0.131837768885	-0.0663495157861	0.0616032517453	-0.108180089455	0.310851913521	-0.0424725712764	-0.0138253526589	0.0288644345407	0.0845798897602	-0.0108267369687	-0.0105408338314	-0.0466426670162	-0.0826830293775	-0.0770603220569	-0.0840112253263	0.0358554356096	0.00121455863338	0.145785040596	0.111979359584	-0.0756382859665	0.073919364052	0.00671301687883	-0.00462204028115	0.0283965070932	0.00715779252839	0.00562381017816	-0.0107294408322	0.0151824116905	0.015986285713	0.009 [...]
+449.F31Nose	-0.00125616651111	0.118308127439	0.0353111308778	-0.0358496445852	-0.0101503061341	0.0572251946759	0.159201255166	-0.0124748465694	0.0633788304522	0.00766555205673	0.126131217709	0.0524115776266	-0.0615234389793	-0.00676320904089	0.0477263128431	-0.0119367695889	0.0290111272246	-0.0295196722603	-0.0534973196624	0.00723137922547	-0.0166898536966	-0.0272902820837	0.0204499192956	-0.00988385002806	0.0557839953401	0.127158411549	-0.0496328631232	-0.0573525900227	0.00535499139385	 [...]
+449.M42Ewxl	0.317733832704	-0.00139975602104	0.083050922225	0.0427708972517	-0.10203831933	0.0149804648424	0.115240912794	0.109168055952	0.00195666626292	0.0244590050344	0.126919144696	-0.0317024936082	0.0944193990064	-0.0743298307839	-0.0862499247738	0.0642073450602	-0.0638170240748	0.0783245811764	0.0778395817069	-0.0275517765466	0.00874301959543	0.0926305370206	0.0393218792407	-0.00598029232854	-0.0331532683997	0.0164457159848	0.0310752260887	-0.0118356283193	0.0139512061721	-0.059440 [...]
+449.M23Urin	0.0830369401493	0.0963676950582	-0.0390460992784	-0.0743175061944	0.194929089551	0.0329182051493	-0.00631353228301	-0.0160622913976	0.00154370838443	-0.214469449473	0.0808084781515	-0.0311498252407	-0.0172480552289	-0.12518171533	-0.0289465023473	0.028462212547	0.106620120809	0.053260469848	-0.0271728046938	-0.03115272497	0.00966549401483	-0.0323592501057	-0.0082364732457	-0.0184634451542	0.00200881411668	-0.0430436337821	-0.057878072426	-0.0174398181534	0.000414350503227	-0. [...]
+449.F32Ewxr	0.0543032510015	-0.0230622983793	-0.117750359598	-0.12983206262	-0.00870249298396	0.0746887814563	0.0166250922573	0.0206072139524	-0.00191989405747	-0.0426714566278	0.0303945567373	-0.0442839271228	0.0779629467072	-0.100088691922	0.0488194429191	0.0186767104849	0.0498106402048	-0.138631062153	0.0120751257945	0.101729475301	0.0821457020821	-0.0228350908057	0.0704583368983	0.00252566856514	-0.0459682573843	0.0694457732213	0.0496167868451	0.0286277183193	-0.057391969934	-0.03421 [...]
+449.F34Urin	0.378097073071	-0.133818013768	0.000603483095612	0.182315679934	0.191252500255	-0.155744650511	0.0140185801273	-0.14701100086	-0.122534533003	0.0250691047251	-0.0174701250036	0.0105110913822	-0.136346079283	0.0581984764947	-0.0774596383177	0.0106809724611	-0.0374032597616	-0.0622433702217	-0.021345942389	0.0515466896264	0.019286966883	-0.0324529772487	0.00713269926044	0.079337816356	0.000466217517219	-0.00802089490113	0.0474758651666	0.0116839603934	0.0246790727209	0.00107812 [...]
+449.M24Ewax	0.341277831374	-0.0222103162588	0.0457650914992	0.10371934372	-0.244906634526	-0.0127482995858	0.0269423655109	-0.0205095802151	0.0179782383179	0.0293208634449	-0.00783330960998	0.0803279832559	0.0967269345421	-0.0294783938613	0.0413090700486	-0.0359214364303	0.0496723769021	0.0593743197406	0.0808096554048	0.00135712603662	-0.0646661564465	-0.0243848598205	-0.0708334416998	-0.0852450247238	0.0314778184766	0.0348804175877	-0.0965963279671	0.0162448953062	-0.0257998601046	-0.04 [...]
+449.F12Urin	0.173779647572	-0.149614701896	0.0150973886249	-0.0707915486009	0.4297225624	-0.0219511247185	0.00882402698829	0.00155282163281	0.00385391110844	0.0724296067928	0.01042952158	0.0255233935613	-0.0764636535432	-0.023892679266	-0.147172417532	0.00336433158442	0.00343077796571	0.109184134462	0.0098550216867	-0.0340937450487	0.0336534974463	-0.0695861243126	0.0669053247628	0.0355708685741	0.0200001845827	-0.031896173612	-0.0113258301211	-0.012055877241	-0.0423881729517	-0.02811336 [...]
+449.M23Uric	0.0313816916485	0.01687248672	0.0293498605018	-0.112844346653	0.262486516302	-0.042076333471	0.0301825837315	0.0513474629122	0.0295502043747	-0.142644140858	-0.0751382319936	-0.127866100756	-0.0235301364871	-0.0812287002818	-0.0236079021737	-0.00486454934922	0.0825554775426	0.112116282519	0.0180714853086	-0.0913351625414	0.0670260627439	-0.0403058794053	0.000595811848347	-0.028427242086	0.0251758873999	-0.0952548593945	-0.00932524826474	0.00726480224575	-0.0351381850398	0.002 [...]
+449.F22Pinr	0.402574397058	-0.0302728223534	0.0353035742925	0.0677807610199	-0.169792080596	0.0321629573031	0.0342759965406	0.139007571677	0.0801890610736	0.0813105174283	0.100994290652	-0.0235401815288	0.0792725436134	-0.00270468448815	-0.0252832227529	0.0398829830688	-0.0272428924737	0.0118314809993	0.0851549193563	-0.0112560663625	0.0665382765414	0.107784797559	-0.0365032689712	-0.00165807953633	-0.000741571729804	-0.00370856400811	-0.0765432754052	-0.0292840797306	-0.0466027877057	-0 [...]
+449.F22Fotl	0.265637156586	0.122309248482	-0.0696323564807	-0.0151189088917	-0.0763309146276	0.102297734539	-0.0671532353924	-0.108712194863	0.12781630641	0.114702242451	0.0309941029926	-0.0339849685018	0.0634340749091	0.101108542659	-0.0212456045857	-0.0297577331521	0.0014109728287	-0.0265095398335	-0.0280145973742	-0.0218914720778	0.0507597824669	0.0202064031371	0.0185513998238	0.0139539878593	0.0976295141608	-0.0309584131848	0.0123086869729	0.0711038008977	0.0238640728425	0.0452226159 [...]
+449.M11Ewxl	0.286543842536	0.00420636099678	0.0421804871683	0.0273923007578	-0.0643179970058	0.00388690329724	-0.0656281413246	0.0354392594778	-0.0634583456931	-0.12547126132	-0.100769872392	-0.0992848646048	-0.128327746659	0.00600178149059	0.00324711344921	-0.0153756884144	-0.062299896864	-0.135853975847	0.0193000712316	-0.0788243075133	-0.130553840804	-0.0204353814425	0.0665235435979	-0.00368396258161	0.0672031771126	-0.0807512650943	-0.0576481348867	0.0256587686974	0.0394147233659	-0. [...]
+449.F34Uric	0.288884972491	-0.21416343066	-0.0207945428494	0.251939693019	0.189611843725	-0.13989349948	0.112680621955	-0.0686025934329	-0.0130040132942	-0.0105193999435	-0.0221468149867	-0.00260312217101	0.0747039662561	0.041829040205	0.0316484781159	-0.0394791836929	-0.0858357806751	-0.0561093483705	0.0476491919544	0.0523228203932	0.0271069257289	-0.0491685490251	0.0302600595073	0.0115634908173	0.010375333954	0.0463799155715	-0.0132961319807	0.017833565582	0.0180457284726	0.01378009182 [...]
+449.M63Urin	0.191919778565	-0.045909937704	0.042148506508	0.0283747151573	0.224538538841	0.00156035542224	0.0529824639014	0.0245468452216	0.0559310126579	-0.0621771217526	0.125575347563	-0.0373630422297	0.127941581001	-0.144707744584	0.0783901915447	0.0268052371786	0.125601716931	-0.0279675172931	-0.111066810423	-0.00572626004264	-0.00415609907846	0.150270158698	0.0215964608946	-0.0627371168053	-0.0599423955461	0.0214094010453	0.0100647635815	0.0706639815977	0.0728630947955	0.03437919596 [...]
+449.F24Uric	0.272350448164	-0.186529006466	0.0353506731131	0.219426965673	0.23245822641	-0.150139045406	0.163165517181	0.00627663364019	-0.023833103896	-0.0229545668592	-0.126336871015	-0.0363478195774	0.0918858374039	0.0685205725374	0.0454531289446	-0.0838730861643	-0.0265323453662	-0.045936509805	-0.0472954320831	0.0414079456599	-0.0393734437494	0.103055828431	-0.0266210117177	-0.0917738418136	-0.0106291437189	0.0424772690959	-0.00278996051907	0.0996063432185	0.0293781113842	0.14044487 [...]
+449.F24Urin	0.229356334777	-0.223105012737	0.0563591399399	0.258020246031	0.245040451205	-0.16239607221	0.157322029455	-0.176762649263	0.0238031088379	-0.0456456272476	-0.0475423462503	0.000674132694656	-0.00116235535747	-0.00772268215947	0.0449368478623	0.0761765254136	-0.0508769503938	0.0245094604933	0.0755547446787	0.0348526923403	-0.0267367476887	0.0695368850722	-0.0443510174119	-0.0787228897629	-0.025899255626	0.000725223097343	0.00603070762263	0.123175844367	0.0143134626167	0.06295 [...]
+449.M24Urin	0.102127117416	-0.0306424734876	0.0521836206229	-0.0910775606457	0.28308916147	-0.0088082355084	0.0904945696393	0.0502566965636	0.0973290122417	-0.146982527304	-0.101976085095	-0.122263609341	-0.00977432190901	-0.069919229353	-0.0268533449621	0.00535454728556	0.0691195304165	0.107990608894	-0.0317760665467	-0.0755983573329	0.0896101051656	-0.0377775059785	0.0392948885135	0.00954265928027	0.0133256284373	-0.0918939545122	0.0224504565882	-0.0124119806894	-0.0162502406543	-0.002 [...]
+449.F33Uric	0.323917845565	-0.18889678652	-0.0274674273743	0.346959409642	0.163409097389	-0.16681652626	0.128140672439	-0.152493024438	-0.116952114033	-0.00424221157726	0.0368493276321	0.049442992492	0.0661787115841	0.0742622333298	-0.000366281288703	-0.00387402630366	0.00102696163592	-0.015632129104	0.0133269329529	-0.0176934334865	-0.0242636095908	-0.101815039366	-0.00697730260563	0.0552024145174	-0.0466786277006	-0.0401534469006	0.0452232781667	-0.106140494564	0.0109427585847	-0.06335 [...]
+449.F23Uric	0.234313266053	-0.130565598077	0.0505564891908	-0.00503564850637	0.355207912296	-0.0630281135131	-6.06282312072e-05	-0.0193651883732	0.0405778321257	0.0194926626726	0.120906881084	0.0456491952327	-0.0601559129299	0.0208621721297	-0.0884629377427	0.113505467062	0.0316309084946	0.0222139856977	-0.015202822361	0.0493885065491	-0.0538184212383	0.0852053872919	-0.0238795742513	-0.0397651726098	-0.0157356550623	0.00464572614388	-0.0312322189386	0.109984637429	-0.00906192693147	0.03 [...]
+449.F23Urin	0.254344424588	-0.222326514674	-0.0554483842518	0.364961613828	0.274004772579	-0.169715683765	0.166883133107	-0.198352484086	-0.131678439055	-0.000943322118736	0.0855079791289	0.0482689647951	0.0945311848005	0.0961798796531	0.0425325090343	0.0363298944888	-0.0504109111185	-0.0657957944896	-0.0116118207222	0.0222226368802	-0.0134734972802	0.0467568087844	-0.0211814565799	-0.0510550537029	-0.0167998236168	-0.0202508853804	-0.000310323020279	0.00174577859706	-0.0644058290107	0.0 [...]
+449.F33Urin	0.274750303384	-0.223431138814	-0.0541489919244	0.385561829494	0.199223530375	-0.168429740772	0.152615335527	-0.183106273199	-0.150095619651	-0.000639375936261	0.0808544306621	0.0648206297865	0.0560533831586	0.116295485066	0.0248639610943	0.0339004777018	-0.0838487777378	-0.0848447104943	0.00337613661214	0.00299932918611	0.0760737887748	-0.0783686739091	0.0103546421546	0.0741510789375	-0.00866508424336	-0.0562739001657	0.00393515599223	-0.13973276876	-0.100986882641	-0.067135 [...]
+449.F24Ewax	0.161479238638	-0.13830861157	0.175069749876	0.0684702805847	0.0393944038314	0.0649046577415	-0.00407445557619	0.17675630209	0.045612735956	-0.0657240884196	0.13026602217	0.0895255616756	0.00270252228797	-0.078369268886	-0.0109138769621	-0.0220076608705	-0.0813011977169	-0.0319676850989	0.00320665434184	-0.0942524931475	-0.141064360308	-0.0375134896492	0.0801626852022	-0.0163422934333	0.124572875511	0.0447534829209	-0.0109962776158	-0.0426719076682	-0.0425024244969	-0.0028483 [...]
+449.F31Urin	0.275365112425	-0.188144259744	-0.0518736742277	0.26503708168	0.242494443756	-0.143050444736	0.105202174407	-0.200134417557	-0.149754355617	0.0203951493313	0.033448944332	0.0359665037185	-0.0454434156852	0.124114374099	-0.0511949452929	0.0119068920787	-0.0916895474989	-0.126134086398	-0.0129745711387	0.030032744958	0.0743142169878	-0.0721470961703	0.0385219500479	0.0710042297954	0.0284989701091	-0.0461601268989	0.0388960422539	-0.108806491368	-0.0594272116806	-0.0489690865792 [...]
+449.F32Urin	0.271728532467	-0.224109062908	-0.0542430213343	0.381885197897	0.240084383123	-0.176586781746	0.168217227598	-0.191034630555	-0.14308509171	0.00406575897866	0.0764772826293	0.0545766526212	0.0784868683036	0.108017032353	0.0205061671657	0.0257670517834	-0.0771686375495	-0.0663148516847	0.00756936047695	-0.000965698788899	0.0540397895435	-0.0645670929989	0.0128570130418	0.0501151857712	-0.00288606855042	-0.0453286545567	0.00197200339431	-0.118484368471	-0.0904925597297	-0.05673 [...]
+449.F32Tong	-0.113417968645	-0.153693422598	0.361570141643	-0.014720236651	-0.0587696993099	0.0389901032095	0.0741020351924	-0.0295539185313	0.10416846694	0.0214596087017	-0.0426364565756	0.0357159987615	0.00866117119529	-0.0192241060379	0.0249383238428	0.0716944655489	-0.0459287714825	0.0114062174071	0.0183006016483	-0.0216970204502	0.0032072445745	-0.00926259494952	-0.0244301071973	0.0384179019442	-0.0532608619634	0.0440255994072	-0.0303769846007	0.0138315063775	-0.024983162997	0.00427 [...]
+449.F34Tong	-0.122446502567	-0.215953279587	0.37471773422	0.00871835010618	0.00679389556888	0.0373111339986	0.0231315380286	-0.0363356738996	0.114536326756	-0.0395788250846	-0.0547719043301	0.0514542765208	-0.0535639494062	-0.0260993357581	0.0388546042143	0.0652387050351	-0.0352487246771	-0.0280162144895	-0.0348170795954	-0.0259576627903	-0.0159830954544	-0.0175353855847	-0.00646525808069	0.027843042809	-0.0245558820367	0.0222102852489	-0.0270964679748	0.00935629009565	-0.00669470994408	 [...]
+449.M14Urin	-0.0932325148546	-0.0554845519843	0.277893463811	-0.0406874721261	0.0877389041354	0.00369132604509	-0.0446715680258	0.0189760106293	-0.0701842487742	-0.0354489291893	0.0315639778933	-0.0375991121862	0.0227319642604	-0.0654382265279	-0.0208625196466	-0.0723054755962	0.0432335188579	-0.0483988822535	-0.0665436417677	-0.0506889719714	-0.0725476713978	0.0250391607971	-0.0075468384926	0.00696485348405	-0.0416028527141	0.00186374641902	-0.00544655313608	-0.0380479323517	0.033368899 [...]
+449.M43Fotl	-0.0534272007197	0.193337728599	-0.0498035418981	0.0426592749658	-0.00703427498583	0.05473173977	0.0157978878209	-0.10270289895	0.0929429157718	-0.0448758882699	0.0328243659026	0.00111940762293	-0.00256900569991	-0.0358572896389	0.098263288628	-0.026617001164	-0.11177717873	-0.00398173516406	0.0347068243684	-0.0940361735093	0.00120930622702	0.0315873976384	0.00765977341628	0.0268585791939	-0.0320219767435	-0.0292233654472	0.0808137766148	0.00685592693913	0.0426125619761	0.022 [...]
+449.F11Tong	-0.0874931253759	-0.227560309846	0.332949734489	0.0242868997782	0.034192579632	0.0291884296942	0.0506627693086	0.00282023493964	0.150241980266	-0.0502361213674	-0.10455619851	0.0858334414762	-0.0459761475422	0.0291872082133	0.0956313204381	0.0646618944097	-0.0330566650899	-0.0206484294199	-0.0101710496721	-0.0361903438966	-0.0159854475217	-0.00754803721797	-0.010001011617	-0.0228466083116	-0.0389582797982	-0.00818574384382	-0.0924471520743	0.0538323341783	-0.0461826699852	-0. [...]
+449.F12Tong	-0.101464668289	-0.227826308043	0.339966647978	0.029076733199	0.0288219680494	0.0323628526611	0.0392701886614	-0.023418213149	0.132110353815	-0.040071590437	-0.0938391079265	0.0819804948123	-0.0410791327106	0.0354115349086	0.0902375488961	0.0613221178232	-0.00989179443649	-0.0284819137035	-0.0212323271101	-0.0173339245111	-0.000682080037897	-0.00920889079113	-0.0108069756079	-0.0129737879198	-0.056712869141	-0.00928647835898	-0.0920240638347	0.0577927417837	-0.0329390319321	- [...]
+449.F22Fotr	0.0369856423431	0.15254223011	0.0127312352535	-0.0363948975454	0.000871939957364	0.122975140965	0.023323730478	-0.00967355833368	0.106644625052	-0.0177387820867	-0.0646777609844	0.0767562810713	0.0928002479259	0.0755257592127	-0.0141008956885	-0.0689447720951	-0.0499769223905	0.0846597970174	-0.0600614242877	-0.0273780835845	-0.00381430097974	-0.0274855965439	-0.0171701835635	0.0237030279975	0.00178407353799	-0.0723872254155	0.0159884743929	-0.0617937170845	0.0761945667927	0. [...]
+449.F13Urin	0.140853517496	-0.160342173623	0.0679952809602	-0.0914619117866	0.366948746795	-0.0453082444276	-0.0500758606078	0.00960757118637	0.109421769402	0.0401988677056	-0.0228954823505	-0.0479933081166	-0.103210062651	-0.0776120536127	-0.048108730265	0.0286200142936	-0.0227752390514	0.165508085192	0.0826901385961	-0.0569125179064	0.0460326454652	-0.0509739143385	0.0427674661545	0.0289873425041	0.102421314493	0.00425980704994	-0.0511362037297	0.00955785228237	-0.0577554330852	0.00445 [...]
+449.F21Frhd	0.317686231605	0.0597529191674	-0.00358617356109	-0.0277285447268	-0.0318482693653	0.00691640206529	0.105811700668	-0.101556737711	-0.0711585138373	-0.00902961384159	-0.0927786263063	-0.0728838381297	-2.1736281311e-05	-0.091440691019	-0.0648009871878	0.00321342733169	-0.0380601746293	-0.0088393915431	-0.0513807933479	0.0577584741878	0.0488663826351	-0.0528289716057	0.0429898043798	0.0462774806101	0.0739781528744	0.00797686702951	0.00447471244722	0.0157962351991	0.029165374099 [...]
+449.F22Frhd	0.194894017464	0.0730304541955	0.0574963059791	-0.126550873589	-0.00471823657505	0.10138941307	0.0270375478383	0.0256437917674	0.0282590236398	-0.0791698670101	0.0187382657995	0.113225973192	-0.00490855131233	-0.00764784978242	-0.0720525874923	0.0182096981378	-0.0755285447915	0.0290064246523	0.0523334039177	0.0616657751715	0.0477273209633	0.0317914595634	-0.0331016298616	0.0207692513853	0.0286408449102	0.0121651869077	-0.0136807436401	0.026595603089	0.00786562193346	0.0387058 [...]
+449.M41Ewxr	0.334305240286	-0.081051160366	0.0248748302451	-0.0453181201338	0.0249176749223	-0.00269614724295	-0.076865498517	0.200192004429	0.0698448540258	-0.0310356692921	0.0407881674612	0.00674580216123	-0.0730117248144	0.0231104454592	-0.0250088061985	0.0255671813907	0.0675165689607	-0.101433024475	0.056952444453	0.0779327339656	0.00857469079294	-0.00290051854417	0.0469608186944	-0.0283698445502	-0.00735505598222	-0.0418603181177	0.0808988373617	0.00946967444548	-0.0352010918001	-0. [...]
+449.F23Fotr	0.395101226263	-0.121062080685	0.00195656595555	0.246567779522	-0.0881837630044	-0.0634054815258	-0.0785137833591	-0.0775358522252	0.0415674715765	0.0129795014148	-0.0264079444613	0.0166486913219	0.0289048637418	0.0862057971165	0.0459380369872	-0.0433819840856	0.0993655468317	0.0918545662809	-0.0124594643048	-0.0457976081167	-0.042452129736	-0.122181655154	-0.0530373681464	0.0695957137882	-0.0846680288389	0.00898389991049	0.0739942048028	0.0311206855338	0.111035916778	0.00403 [...]
+449.M13Knee	0.0713629053459	0.0515183179978	-0.0699721471804	-0.0660435538208	0.125958759136	0.0739320087347	-0.227414433373	-0.0358371880493	0.0243018629648	-0.175463581622	0.014476179777	-0.0523351012289	-0.0266205411175	0.034061040447	0.00487578486333	0.000704298732704	-0.202608521855	0.0372594658173	-0.0759140539687	0.0897134877234	-0.000463338162332	0.0264191499202	0.0681000842448	0.0250816085425	-0.00671296404204	0.0786297691164	-0.0382459227274	0.0130738665695	-0.061886711785	-0.0 [...]
+449.M53Frhd	0.289585495718	0.118978539226	-0.0303753234466	-0.0554432744569	-0.120372501826	0.0383202009994	0.0220970880147	-0.108287325425	-0.0783218244433	-0.0770218053571	-0.0163892905181	-0.040069720298	0.0146858032033	-0.0892572238205	-0.0380267136991	0.0224093871891	0.0436944177289	-0.00744485802114	-0.0126422376949	-0.00494593269386	0.0231746632957	0.0213102456812	0.0057441325701	-0.0485262202567	0.0301935039379	-0.0553911116348	0.0528423073625	0.0308194419394	-0.027094020961	-0.0 [...]
+449.M12Aptl	0.266626337541	0.142079197399	-0.0730741663053	-0.0485314327318	-0.0982300240404	0.0419032133478	-0.0543491157725	-0.175145865461	0.0173545382488	-0.025048309523	-0.0103522640345	-0.115479346968	0.0209958836997	0.0590093206425	-0.0067194941425	0.0383987263804	0.0701421641353	-0.0271234312949	-0.00313877178312	-0.015610281393	-0.0315642472137	0.0498456361083	0.00389792229184	-0.0195225542039	-0.0149414953701	0.0354559254416	-0.0536166010639	0.0283894595532	0.0326940476169	-0.0 [...]
+449.M41Fotr	0.261546502546	0.0602806221005	-0.0283029957508	0.0608206741383	-0.142944408491	0.0830840376995	0.0115515065134	-0.176429195646	0.0641637740063	-0.0306942712891	-0.0281734528943	-0.0237018676223	0.126086170827	0.0188796094826	-0.004015730924	0.0185792242272	0.0260790633603	0.106517284551	-0.0170526364848	-0.0740250220024	-0.0560687932449	-0.0523246495985	-0.0282085301327	0.0264906554893	-0.0869566639133	-0.0122831344599	0.0354801081735	0.0723033967739	0.0839205598027	-0.03753 [...]
+449.M41Fotl	0.360350082148	0.0491637116576	-0.0183564977531	-0.0142855605272	0.00192125858303	-0.00338028300016	-0.0139308507687	-0.0796724265478	0.0927478447114	0.174075678614	0.0468574509191	-0.0608025516987	0.0747012351947	0.075696314191	-0.055511753797	-0.0280186248432	0.0425191467097	0.00469142632215	0.044109056718	-0.0526582940885	-0.0326560159956	0.0189222510119	-0.00271008692003	0.00514504867629	0.0562167127978	0.0141669591483	0.0287891866886	0.0455239439453	-0.030368241924	-0.04 [...]
+449.M42Fotl	0.188987545048	0.0971015526591	-0.0440430153097	-0.0194707704069	-0.0468152469389	0.110920630149	0.0142376251246	-0.106632449274	0.139859880636	0.0394772801724	-0.0248972825987	0.00247276224288	0.0641849331947	0.0815121340722	-0.0613563838685	-0.0718941289802	-0.00765344871358	-0.00446725184452	0.0493779269035	-0.0304451082628	-0.0321096707284	-0.016501440412	0.00711388398994	-0.0048268694534	0.0254636698327	0.0380631309302	0.0891067927622	0.0662415456152	0.0212954614324	-0.0 [...]
+449.F14Urin	0.211404362274	-0.153322492372	0.0668998291139	-0.0308896332635	0.342316486512	0.0130813781623	0.0388620413567	0.070293325498	0.0909967940876	0.0203372562347	0.00534643712144	-0.00889429508777	-0.0494041972224	-0.0250797906693	-0.145063367961	-0.00504723555691	0.00782299812018	0.118699892323	0.000175788056494	-0.0561973515535	0.0376136289009	-0.0611048352808	0.0828146040483	0.0246563474742	0.0217804226569	-0.0281989682098	0.011631612872	0.0176528240141	-0.0110506538846	-0.061 [...]
+449.M13Ewax	0.453770404053	-0.136335480579	0.000296170068617	0.293775770095	-0.162169839067	-0.112312311912	-0.0901355312419	0.150123069146	-0.0229387704439	-0.0476585458478	-0.00216505587727	-0.0100240427144	-0.0234684503098	-0.0126359365533	0.10003309019	-0.0315621603456	0.021766016519	-0.00109624630963	0.0248698836991	-0.0275038567636	0.0353475467668	-0.0325464629948	-0.000953853841138	0.00260759887468	0.0313932666033	-0.0059941037911	-0.0531555432075	-0.0290135201712	0.0311961937845	 [...]
+449.F24Fotl	0.306669256352	-0.0301922171454	0.0190689406366	0.0847354819185	-0.137426182399	0.100545394107	0.00596768152343	-0.0865820916846	0.178080636902	0.131981058171	0.0896159538909	0.0999803389078	0.153402564056	0.0741780784666	0.0222216407529	-0.0571002347788	0.0368095050919	0.101625350608	0.0146051996455	-0.0544122891439	0.013649750597	-0.0204816521483	-0.0594646662272	-0.0133767022514	0.0253792231851	-0.0125986377822	-0.0219596459744	0.0303428269836	-0.0111685756071	0.0133912196 [...]
+449.F21Pinr	0.399103206959	-0.0312430621704	0.0463055286867	0.135886685014	-0.142403902302	-0.07685883495	0.123094267863	0.0570752954184	-0.0184688319228	0.0306870354329	-0.00981854636333	-0.0822424444234	0.0915201223743	-0.0775158597229	-0.032997907858	0.0415610869201	-0.0405548732785	0.0417703478831	0.0558041637103	0.0170192756582	-0.0646095821138	0.013770555228	-0.0254222648359	-0.0162688570455	-0.0362539126903	0.010117059182	-0.0591963784594	0.0113667139372	-2.97166665538e-05	-0.0839 [...]
+449.M31Aptl	0.398222683646	0.0733166730477	-0.0349157365999	-0.0707620319614	-0.118151796159	-0.0245037825405	-0.0438573665262	-0.129313519657	-0.0147045783513	0.116465861015	-0.00619102125189	-0.118808237449	-0.0101963822041	0.0292101969765	-0.0268615453378	0.0461900847834	0.122734335971	-0.0736353418246	0.0107403335729	-0.0204824154738	0.0136797786568	0.00927981433311	-0.0694203488456	-0.0115336558731	0.0170445939597	-0.0503075340513	-0.0928343397315	0.0414625923478	-0.00786117290842	0 [...]
+449.M32Aptl	0.378997360724	0.0939037785448	-0.0367380509788	-0.0537966506605	-0.142933560138	0.0244515470406	-0.0083419480854	-0.146596343513	-0.0141580872879	0.0664911310851	-0.0344591346926	-0.129390467295	0.00708639807954	-0.0240283937165	-0.0188892451026	0.0192364465558	0.12508829155	-0.0376408711365	-0.0563246183231	-0.0240840406409	0.0385487298414	-0.0463963167365	-0.0194626870524	0.009675261181	0.0581553943531	-0.0260041000302	-0.040473981115	-0.00453944361907	-0.0122076140241	0.0 [...]
+449.M33Ewax	0.179100732157	-0.0832746292489	0.155039007986	0.0495735894639	-0.0594094663987	0.085473921076	-0.0336697869383	0.127198972107	0.0127558438252	-0.102919111569	0.153378464251	0.172741250584	-0.00212518610348	-0.0661105167628	-0.071795486319	-0.042280703501	-0.0355347529022	0.112771177373	0.0561269972014	0.0227349530234	-0.0622472159026	0.0477871601796	-0.0596368658473	-0.0197202407443	-0.0564991145374	0.0114489421611	0.123851872467	-0.0558292185884	-0.0026658565184	-0.00224865 [...]
+449.M31Ewxl	0.413584473544	-0.0318995309822	0.042690126923	0.117115004879	-0.216071546981	0.00337655528808	0.0437132557631	0.0113586495823	-0.0311861248195	0.0254486883756	-0.00898628435496	-0.0349180953995	0.0387924052849	-0.129164038836	-0.0478893551498	0.0422325267029	-0.0459329114572	0.0909882752097	-0.0342865543101	0.0247250405967	-0.00264804111566	-0.0407138695514	0.00404778596946	0.0534235034866	-0.0438965627511	0.0301664944258	0.034175015484	0.0463368316692	0.0429261119971	-0.012 [...]
+449.F23Ewax	0.461485309696	-0.141663937487	0.0236325966034	0.290241176323	-0.149545236976	-0.117758639229	-0.0550941996073	0.159370197136	-0.0424558331541	-0.0647168633092	-0.0297515776675	0.00207462468022	-0.0450158648972	-0.0464453230052	0.0561139569728	-0.0159864204089	0.00997767462711	0.0257364439015	0.0216352159566	-0.00462806986837	-0.0107442148879	-0.047013180673	-0.0162547544808	0.0172314583747	-0.0267527978383	-0.0199162473173	-0.0139513271907	-0.0167217237764	0.0540774439329	0. [...]
+449.F14Ewax	0.319795228131	-0.0410986073778	0.00475882836592	0.174115035744	-0.162305908872	0.0412944208525	-0.0421244283209	0.0487426417052	-0.0257454455646	-0.167131297386	-0.0630516148894	0.0538728458474	-0.0154021937148	-0.110166942367	0.0614824629087	-0.0853334920593	0.00840897146994	0.0652367594685	-0.0641788111829	-0.0499126944104	0.0274335820098	0.0197407355499	0.0268388622004	-0.060968051896	0.0933356365231	0.0725170958852	-0.0533026579545	-0.036276407645	-0.0750720987811	0.0249 [...]
+449.F23Fotl	0.402584987113	-0.0196598389556	0.00938205780319	0.111633018464	-0.186733421847	0.00982401882748	0.0218306273987	-0.0884043760882	0.0549974688103	0.0850772633514	-0.0330338261657	-0.0480206727829	0.106665714132	-0.0502370362332	-0.0171689306884	0.00736408951972	0.0561989432445	0.130313755427	-0.0344564852116	-0.0226662420958	-0.0284133268808	-0.093828816694	-0.0409924276915	0.0574951503162	-0.0574401870566	0.032488448727	0.0318600806194	0.0343700978787	0.069659175752	0.013836 [...]
+449.F22Ewxl	0.459940329389	-0.125854630123	0.00887246303222	0.259519794553	-0.164858326135	-0.0820909732811	-0.0700113375319	0.177801980284	-0.0138527236644	-0.0778301484107	0.0154211160266	-0.0296672088963	-0.0162233556868	-0.0430985963097	0.0533014686465	0.00278068594273	0.000780866082616	-0.00726499893475	0.0412712881189	-0.0501501108919	0.0527316281347	0.0448199574008	0.0160785217348	-0.0168740112563	0.0232670831194	-0.0239841553414	-0.0572923763861	0.0189164991172	0.015159495393	-0. [...]
+449.M14Ewax	0.464759013852	-0.144182325383	0.00223406860158	0.300819019316	-0.157920263677	-0.119029412488	-0.0811058008974	0.17673388902	-0.0456477898874	-0.046127177873	0.0108247522532	-0.00796115768757	-0.0372925904713	-0.0280424474929	0.0951504125493	-0.0200222391386	0.003092644629	-0.00143164149295	0.0178498846659	-0.0206062254655	0.0476638486708	-0.00694846912349	-0.00765025334117	0.00614930806024	0.0243306536434	-0.0125343449425	-0.0540972114095	-0.0292077770669	0.000600873662031	 [...]
+449.M31Ewxr	0.368677459555	-0.116742732815	0.0571128180172	0.029996967433	0.061586167184	-0.0177297250545	-0.169239776686	0.200615987618	0.0727623626106	0.0230203858001	0.126313903233	0.0520037969104	-0.133026859714	0.0524404147829	-0.0301617410807	0.0721014258904	0.0472038203874	-0.0130598258931	-0.0684530382208	0.059914671568	0.0453625404574	0.0110211808922	0.015802329474	0.0399756551717	0.048313685464	-0.01571992953	-0.0188636635165	-0.000133438787951	-0.0266642603911	0.0410299224885	 [...]
+449.M41Ewxl	0.456764913568	-0.0868741922781	-0.000848658352481	0.231349295248	-0.229325094823	-0.0769671041245	0.0204121703377	0.107761143414	0.00615030479453	0.0744552684325	0.0257486880325	-0.0602314075407	0.0796451123778	-0.0478455130793	0.0437171695172	0.0258143028078	-0.0352215611593	0.0419991239321	0.0356037977539	0.0319719237083	0.0557833554514	-0.025045744551	-0.0341469661378	0.0182284726782	0.0299057368208	-0.00930388741748	-0.107463808327	0.0130161165262	-0.004190993252	0.01628 [...]
+
+Biplot	0	0
+
+Site constraints	0	0
diff --git a/examples/evident.ipynb b/examples/evident.ipynb
new file mode 100644
index 0000000..3d52ba5
--- /dev/null
+++ b/examples/evident.ipynb
@@ -0,0 +1,417 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If you are not using GitHub [click here to open the notebook using nbviewer](http://nbviewer.jupyter.org/github/biocore/emperor/blob/new-api/examples/evident.ipynb)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook replicates part of the [E-vident](https://github.com/biocore/evident) analysis platform, allowing you to explor a series of different distance metrics, and rarefaction levels by leveraging the Jupyter interface available in **Emperor**.\n",
+    "\n",
+    "Before you execute this example, you need to make sure you install a few additional dependencies:\n",
+    "\n",
+    "```\n",
+    "pip install scikit-learn ipywidgets h5py biom-format\n",
+    "```\n",
+    "\n",
+    "Once you've done this, you will need to enable the `ipywidgets` interface, to do so, you will need to run:\n",
+    "\n",
+    "```\n",
+    "jupyter nbextension enable --py widgetsnbextension\n",
+    "```\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "%matplotlib inline\n",
+    "from __future__ import division\n",
+    "\n",
+    "# biocore\n",
+    "from emperor.qiime_backports.parse import parse_mapping_file\n",
+    "from emperor.qiime_backports.format import format_mapping_file\n",
+    "from emperor import Emperor, nbinstall\n",
+    "\n",
+    "nbinstall()\n",
+    "\n",
+    "from skbio.stats.ordination import pcoa\n",
+    "from skbio.diversity import beta_diversity\n",
+    "from skbio import TreeNode\n",
+    "from skbio.io.util import open_file\n",
+    "\n",
+    "from biom import load_table\n",
+    "from biom.util import biom_open\n",
+    "\n",
+    "import qiime_default_reference\n",
+    "\n",
+    "# pydata/scipy\n",
+    "import pandas as pd\n",
+    "import numpy as np\n",
+    "\n",
+    "from scipy.spatial.distance import braycurtis, canberra\n",
+    "from ipywidgets import interact\n",
+    "from sklearn.metrics import pairwise_distances\n",
+    "from functools import partial\n",
+    "\n",
+    "import warnings\n",
+    "\n",
+    "warnings.filterwarnings(action='ignore', category=Warning)\n",
+    "\n",
+    "# -1 means all the processors available\n",
+    "pw_dists = partial(pairwise_distances, n_jobs=-1)\n",
+    "\n",
+    "def load_mf(fn):\n",
+    "    with open_file(fn) as f:\n",
+    "        mapping_data, header, _ = parse_mapping_file(f)\n",
+    "        _mapping_file = pd.DataFrame(mapping_data, columns=header)\n",
+    "        _mapping_file.set_index('SampleID', inplace=True)\n",
+    "    return _mapping_file\n",
+    "\n",
+    "def write_mf(f, _df):\n",
+    "    with open(f, 'w') as fp:\n",
+    "        lines = format_mapping_file(['SampleID'] + _df.columns.tolist(),\n",
+    "                                    list(_df.itertuples()))\n",
+    "        fp.write(lines+'\\n')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We are going to load data from [Fierer et al. 2010](http://www.pnas.org/content/107/14/6477.full) (the data was retrieved from study [232](https://qiita.ucsd.edu/study/description/232) in [Qiita](https://qiita.ucsd.edu), remember you need to be logged in to access the study).\n",
+    "\n",
+    "We will load this as a [QIIME](http://qiime.org) mapping file and as a [BIOM](http://biom-format.org) OTU table."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "mf = load_mf('keyboard/mapping-file.txt')\n",
+    "bt = load_table('keyboard/otu-table.biom')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we will load a reference database using [scikit-bio](http://scikit-bio.org)'s TreeNode object. The reference itself is as provided by [Greengenes](http://greengenes.secondgenome.com/downloads)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "tree = TreeNode.read(qiime_default_reference.get_reference_tree())\n",
+    "\n",
+    "for n in tree.traverse():\n",
+    "    if n.length is None:\n",
+    "        n.length = 0"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The function `evident` uses the OTU table (`bt`), the mapping file (`mf`), and the phylogenetic tree (`tree`), to construct a distance matrix and ordinate it using principal coordinates analysis.\n",
+    "\n",
+    "To exercise this function, we build a small ipywidgets function that will let us experiment with a variety of rarefaction levels and distance metrics."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def evident(n, metric):\n",
+    "    rarefied = bt.subsample(n)\n",
+    "    data = np.array([rarefied.data(i) for i in rarefied.ids()], dtype='int64')\n",
+    "    \n",
+    "    if metric in ['unweighted_unifrac', 'weighted_unifrac']:\n",
+    "        res = pcoa(beta_diversity(metric, data, rarefied.ids(),\n",
+    "                                  otu_ids=rarefied.ids('observation'),\n",
+    "                                  tree=tree, pairwise_func=pw_dists))\n",
+    "    else:\n",
+    "        res = pcoa(beta_diversity(metric, data, rarefied.ids(),\n",
+    "                                  pairwise_func=pw_dists))\n",
+    "    return Emperor(res, mf, remote=True)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Note** that the ipywidgets themselves, will not be visible unless you are executing this notebook i.e. by running your own Jupyter server."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "\n",
+       "if ($(\"#emperor-css\").length == 0){{\n",
+       "    $(\"head\").append([\n",
+       "\n",
+       "        '<link id=\"emperor-css\" rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/css/emperor.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery-ui.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/slick.grid.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/spectrum.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/chosen.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery.contextMenu.min.css\">'\n",
+       "    ]);\n",
+       "}}\n",
+       "</script>\n",
+       "\n",
+       "<div id='emperor-notebook-0x591b1cda' style=\"position: relative; width:100%; height:500px;\">\n",
+       "  <div class='loading' style=\"position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px\"><img src='https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files'></div>\n",
+       "</div>\n",
+       "</div>\n",
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "requirejs.config({\n",
+       "// the left side is the module name, and the right side is the path\n",
+       "// relative to the baseUrl attribute, do NOT include the .js extension\n",
+       "'paths': {\n",
+       "  /* jQuery */\n",
+       "  'jquery': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-2.1.4.min',\n",
+       "  'jqueryui': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-ui.min',\n",
+       "  'jquery_drag': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',\n",
+       "\n",
+       "  /* jQuery plugins */\n",
+       "  'chosen': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chosen.jquery.min',\n",
+       "  'spectrum': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/spectrum.min',\n",
+       "  'position': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.ui.position.min',\n",
+       "  'contextmenu': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.contextMenu.min',\n",
+       "\n",
+       "  /* other libraries */\n",
+       "  'underscore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/underscore-min',\n",
+       "  'chroma': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chroma.min',\n",
+       "  'filesaver': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/FileSaver.min',\n",
+       "  'blob': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/Blob',\n",
+       "  'd3': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/d3.min',\n",
+       "\n",
+       "\n",
+       "  /* THREE.js and plugins */\n",
+       "  'three': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.min',\n",
+       "  'orbitcontrols': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',\n",
+       "\n",
+       "  /* SlickGrid */\n",
+       "  'slickcore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.core.min',\n",
+       "  'slickgrid': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.grid.min',\n",
+       "  'slickformatters': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.editors.min',\n",
+       "  'slickeditors': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.formatters.min',\n",
+       "\n",
+       "  /* Emperor's objects */\n",
+       "  'util': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/util',\n",
+       "  'model': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/model',\n",
+       "  'view': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view',\n",
+       "  'controller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/controller',\n",
+       "  'draw': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/draw',\n",
+       "  'scene3d': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/sceneplotview3d',\n",
+       "  'viewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view-controller',\n",
+       "  'colorviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-view-controller',\n",
+       "  'visibilitycontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/visibility-controller',\n",
+       "  'scaleviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-view-controller',\n",
+       "  'shapecontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-controller',\n",
+       "  'axescontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/axes-controller',\n",
+       "  'shape-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-editor',\n",
+       "  'color-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-editor',\n",
+       "  'scale-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-editor',\n",
+       "  'shapes': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shapes'\n",
+       "},\n",
+       "/*\n",
+       "   Libraries that are not AMD compatible need shim to declare their\n",
+       "   dependencies.\n",
+       " */\n",
+       "'shim': {\n",
+       "  'jquery_drag': {\n",
+       "    'deps': ['jquery', 'jqueryui']\n",
+       "  },\n",
+       "  'chosen': {\n",
+       "    'deps': ['jquery'],\n",
+       "    'exports': 'jQuery.fn.chosen'\n",
+       "  },\n",
+       "  'contextmenu' : {\n",
+       "    'deps': ['jquery', 'jqueryui', 'position']\n",
+       "  },\n",
+       "  'filesaver' : {\n",
+       "    'deps': ['blob']\n",
+       "  },\n",
+       "  'orbitcontrols': {\n",
+       "    'deps': ['three']\n",
+       "  },\n",
+       "'slickcore': ['jqueryui'],\n",
+       "'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',\n",
+       "              'slickeditors']\n",
+       "}\n",
+       "});\n",
+       "\n",
+       "requirejs(\n",
+       "[\"jquery\", \"model\", \"controller\"],\n",
+       "function($, model, EmperorController) {\n",
+       "  var DecompositionModel = model.DecompositionModel;\n",
+       "\n",
+       "  var div = $('#emperor-notebook-0x591b1cda');\n",
+       "\n",
+       "  var ids = ['232.M9Thmr217', '232.M3Rinr217', '232.M2Enter217', '232.M3Midr217', '232.M3Tkey217', '232.M2Okey217', '232.M9Hkey217', '232.M9Pinl217', '232.M9Midl217', '232.M9Rinl217', '232.M2Midr217', '232.M2Lsft217', '232.M9Mkey217', '232.M3Wkey217', '232.M9Gkey217', '232.M3Midl217', '232.M3Pinl217', '232.M9Vkey217', '232.M2Tkey217', '232.M9Dkey217', '232.M2Gkey217', '232.M3Lkey217', '232.M9Pkey217', '232.M2Ykey217', '232.M2Ikey217', '232.M9Midr217', '232.M9Rinr217', '232.M2Lkey [...]
+       "  var coords = [[0.11767371899988194, 0.15045943821609134, 0.13143983529654077, -0.03792290078500057, -0.009586044527414678], [0.07713844369285888, -0.21039597819005887, 0.0863235874648861, 0.04080743908086652, 0.09679702485034439], [-0.30562281853445517, 0.026797677660518965, 0.005010595306559895, -0.04322845007211838, 0.06934938421008377], [0.08865128525126652, -0.19599477772461418, 0.05863229416460895, -0.2520552325264606, -0.06974849802574015], [0.15992366626085133, -0.098269 [...]
+       "  var pct_var = [23.49638562408787, 9.381085995228345, 5.481830154292925, 3.809425921975831, 3.7661403883378983];\n",
+       "  var md_headers = ['SampleID', 'BarcodeSequence', 'LinkerPrimerSequence', 'center_name', 'center_project_name', 'emp_status', 'experiment_design_description', 'key_seq', 'library_construction_protocol', 'linker', 'platform', 'region', 'run_center', 'run_date', 'run_prefix', 'samp_size', 'sample_center', 'sequencing_meth', 'study_center', 'target_gene', 'target_subfragment', 'age', 'age_unit', 'altitude', 'anonymized_name', 'assigned_from_geo', 'body_habitat', 'body_product', 'bo [...]
+       "  var metadata = [['232.M9Thmr217', 'ACTACGTGTGGT', 'CATGCTGCCTCCCGTAGGAGT', 'CCME', 'Forensic_identification_using_skin_bacterial_communities', 'EMP', 'Forensic_identification_using_skin_bacterial_communities', 'TCAG', '16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_thos [...]
+       "  var axesNames = ['PC1', 'PC2', 'PC3', 'PC4', 'PC5'];\n",
+       "\n",
+       "  var dm, ec;\n",
+       "\n",
+       "  function init() {\n",
+       "    // Initialize the DecompositionModel\n",
+       "    dm = new DecompositionModel(name, ids, coords, pct_var,\n",
+       "                                md_headers, metadata, axesNames);\n",
+       "    // Initialize the EmperorController\n",
+       "    ec = new EmperorController(dm, 'emperor-notebook-0x591b1cda');\n",
+       "  }\n",
+       "\n",
+       "  function animate() {\n",
+       "    requestAnimationFrame(animate);\n",
+       "    ec.render();\n",
+       "  }\n",
+       "  $(window).resize(function() {\n",
+       "    ec.resize(div.innerWidth(), div.innerHeight());\n",
+       "  });\n",
+       "\n",
+       "  $(function(){\n",
+       "    init();\n",
+       "    animate();\n",
+       "\n",
+       "  });\n",
+       "\n",
+       "}); // END REQUIRE.JS block\n",
+       "</script>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<emperor.core.Emperor at 0x11f26de80>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "interact(evident, n=(200, 2000, 50),\n",
+    "         metric=['unweighted_unifrac', 'weighted_unifrac', 'braycurtis', 'euclidean'],\n",
+    "         __manual=True)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  },
+  "widgets": {
+   "state": {
+    "062306f79e4b4713b9ab259b8d6c3f90": {
+     "views": []
+    },
+    "2357c429454345b0bf544e5e0b9ab061": {
+     "views": []
+    },
+    "32770a3826544abd8a44986dddb91a7b": {
+     "views": []
+    },
+    "5d80be2b8f23473fa49def1aea2d99af": {
+     "views": []
+    },
+    "6fb97a62b3e547709dc1256bb7ce1608": {
+     "views": []
+    },
+    "7ca56e9087f648fda1edd4c7ad25e20c": {
+     "views": []
+    },
+    "8760dc4ef28145eab8034a900cd6982c": {
+     "views": []
+    },
+    "94456d752a064b7fbdec6a62ab71fc1b": {
+     "views": []
+    },
+    "9523e6b612cc4e6b8f1158955f3e2932": {
+     "views": []
+    },
+    "abf30dabd57b428d9e0d6e8795f764a8": {
+     "views": []
+    },
+    "b6bf52be82c64575ab0d68ddd517ce41": {
+     "views": []
+    },
+    "c89604bff1f14f1d9bde0778ae0a84fd": {
+     "views": []
+    },
+    "d4d02d0e64c74d6eac2b0988e2733f16": {
+     "views": []
+    },
+    "e800d0b6881c4646ad5e1f92dde0eb13": {
+     "views": []
+    },
+    "eae1f31c98484f57bbb519ecdd9169c0": {
+     "views": []
+    },
+    "f044acc7d3ec43a3888daec4f6c97994": {
+     "views": []
+    }
+   },
+   "version": "1.1.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/images/costello-all.png b/examples/images/costello-all.png
new file mode 100644
index 0000000..26a9e06
Binary files /dev/null and b/examples/images/costello-all.png differ
diff --git a/examples/images/costello-colored.png b/examples/images/costello-colored.png
new file mode 100644
index 0000000..1f0adec
Binary files /dev/null and b/examples/images/costello-colored.png differ
diff --git a/examples/images/costello.png b/examples/images/costello.png
new file mode 100644
index 0000000..edbbed4
Binary files /dev/null and b/examples/images/costello.png differ
diff --git a/examples/images/distance-matrix.png b/examples/images/distance-matrix.png
new file mode 100644
index 0000000..a04df20
Binary files /dev/null and b/examples/images/distance-matrix.png differ
diff --git a/examples/images/glitch.gif b/examples/images/glitch.gif
new file mode 100644
index 0000000..f1be685
Binary files /dev/null and b/examples/images/glitch.gif differ
diff --git a/examples/images/js-doc.png b/examples/images/js-doc.png
new file mode 100644
index 0000000..651e9bd
Binary files /dev/null and b/examples/images/js-doc.png differ
diff --git a/examples/images/knight-logo.png b/examples/images/knight-logo.png
new file mode 100644
index 0000000..e47578d
Binary files /dev/null and b/examples/images/knight-logo.png differ
diff --git a/examples/images/main-doc.png b/examples/images/main-doc.png
new file mode 100644
index 0000000..f320937
Binary files /dev/null and b/examples/images/main-doc.png differ
diff --git a/examples/images/microbes-metric.png b/examples/images/microbes-metric.png
new file mode 100644
index 0000000..c71dfb9
Binary files /dev/null and b/examples/images/microbes-metric.png differ
diff --git a/examples/images/microbes.png b/examples/images/microbes.png
new file mode 100644
index 0000000..43b1be3
Binary files /dev/null and b/examples/images/microbes.png differ
diff --git a/examples/images/python-doc-2.png b/examples/images/python-doc-2.png
new file mode 100644
index 0000000..483bc8a
Binary files /dev/null and b/examples/images/python-doc-2.png differ
diff --git a/examples/images/python-doc.png b/examples/images/python-doc.png
new file mode 100644
index 0000000..75994c5
Binary files /dev/null and b/examples/images/python-doc.png differ
diff --git a/examples/images/qiime_logo_large.png b/examples/images/qiime_logo_large.png
new file mode 100644
index 0000000..8c5ad49
Binary files /dev/null and b/examples/images/qiime_logo_large.png differ
diff --git a/examples/images/table-2.png b/examples/images/table-2.png
new file mode 100644
index 0000000..07cc1e5
Binary files /dev/null and b/examples/images/table-2.png differ
diff --git a/examples/images/table.png b/examples/images/table.png
new file mode 100644
index 0000000..06a105c
Binary files /dev/null and b/examples/images/table.png differ
diff --git a/examples/images/vroom.png b/examples/images/vroom.png
new file mode 100644
index 0000000..1859c6e
Binary files /dev/null and b/examples/images/vroom.png differ
diff --git a/examples/keyboard.ipynb b/examples/keyboard.ipynb
new file mode 100644
index 0000000..8dc330e
--- /dev/null
+++ b/examples/keyboard.ipynb
@@ -0,0 +1,295 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If you are not using GitHub [click here to open the notebook using nbviewer](http://nbviewer.jupyter.org/github/biocore/emperor/blob/new-api/examples/keyboard.ipynb)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Emperor's Python API\n",
+    "\n",
+    "**This notebook demonstrate Emperor's new Python API, which can and will change as we continue to exercise this interface, for more information, have a look at the [pull request here](https://github.com/biocore/emperor/pull/405).**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "import pandas as pd, numpy as np\n",
+    "from emperor import Emperor, nbinstall\n",
+    "from skbio import OrdinationResults\n",
+    "\n",
+    "from emperor.qiime_backports.parse import parse_mapping_file\n",
+    "from emperor.qiime_backports.format import format_mapping_file\n",
+    "\n",
+    "from skbio.io.util import open_file\n",
+    "\n",
+    "nbinstall()\n",
+    "\n",
+    "def load_mf(fn):\n",
+    "    with open_file(fn) as f:\n",
+    "        mapping_data, header, _ = parse_mapping_file(f)\n",
+    "        _mapping_file = pd.DataFrame(mapping_data, columns=header)\n",
+    "        _mapping_file.set_index('SampleID', inplace=True)\n",
+    "    return _mapping_file\n",
+    "\n",
+    "def write_mf(f, _df):\n",
+    "    with open(f, 'w') as fp:\n",
+    "        lines = format_mapping_file(['SampleID'] + _df.columns.tolist(),\n",
+    "                                    list(_df.itertuples()))\n",
+    "        fp.write(lines+'\\n')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We are going to load data from [Fierer et al. 2010](http://www.pnas.org/content/107/14/6477.full) (the data was retrieved from study [232](https://qiita.ucsd.edu/study/description/232) in [Qiita](https://qiita.ucsd.edu), remember you need to be logged in to access the study).\n",
+    "\n",
+    "Specifically, here we will reproduce *Figure 1 A*."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "mf = load_mf('keyboard/mapping-file.txt')\n",
+    "res = OrdinationResults.read('keyboard/unweighted-unifrac.even1000.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# change the remote parameter to False/True depending on what you want to do\n",
+    "x = Emperor(res, mf, remote=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "\n",
+       "if ($(\"#emperor-css\").length == 0){{\n",
+       "    $(\"head\").append([\n",
+       "\n",
+       "        '<link id=\"emperor-css\" rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/css/emperor.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery-ui.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/slick.grid.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/spectrum.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/chosen.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery.contextMenu.min.css\">'\n",
+       "    ]);\n",
+       "}}\n",
+       "</script>\n",
+       "\n",
+       "<div id='emperor-notebook-0x4b24c820' style=\"position: relative; width:100%; height:500px;\">\n",
+       "  <div class='loading' style=\"position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px\"><img src='https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files'></div>\n",
+       "</div>\n",
+       "</div>\n",
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "requirejs.config({\n",
+       "// the left side is the module name, and the right side is the path\n",
+       "// relative to the baseUrl attribute, do NOT include the .js extension\n",
+       "'paths': {\n",
+       "  /* jQuery */\n",
+       "  'jquery': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-2.1.4.min',\n",
+       "  'jqueryui': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-ui.min',\n",
+       "  'jquery_drag': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',\n",
+       "\n",
+       "  /* jQuery plugins */\n",
+       "  'chosen': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chosen.jquery.min',\n",
+       "  'spectrum': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/spectrum.min',\n",
+       "  'position': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.ui.position.min',\n",
+       "  'contextmenu': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.contextMenu.min',\n",
+       "\n",
+       "  /* other libraries */\n",
+       "  'underscore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/underscore-min',\n",
+       "  'chroma': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chroma.min',\n",
+       "  'filesaver': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/FileSaver.min',\n",
+       "  'blob': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/Blob',\n",
+       "  'd3': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/d3.min',\n",
+       "\n",
+       "\n",
+       "  /* THREE.js and plugins */\n",
+       "  'three': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.min',\n",
+       "  'orbitcontrols': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',\n",
+       "\n",
+       "  /* SlickGrid */\n",
+       "  'slickcore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.core.min',\n",
+       "  'slickgrid': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.grid.min',\n",
+       "  'slickformatters': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.editors.min',\n",
+       "  'slickeditors': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.formatters.min',\n",
+       "\n",
+       "  /* Emperor's objects */\n",
+       "  'util': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/util',\n",
+       "  'model': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/model',\n",
+       "  'view': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view',\n",
+       "  'controller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/controller',\n",
+       "  'draw': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/draw',\n",
+       "  'scene3d': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/sceneplotview3d',\n",
+       "  'viewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view-controller',\n",
+       "  'colorviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-view-controller',\n",
+       "  'visibilitycontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/visibility-controller',\n",
+       "  'scaleviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-view-controller',\n",
+       "  'shapecontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-controller',\n",
+       "  'axescontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/axes-controller',\n",
+       "  'shape-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-editor',\n",
+       "  'color-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-editor',\n",
+       "  'scale-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-editor',\n",
+       "  'shapes': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shapes'\n",
+       "},\n",
+       "/*\n",
+       "   Libraries that are not AMD compatible need shim to declare their\n",
+       "   dependencies.\n",
+       " */\n",
+       "'shim': {\n",
+       "  'jquery_drag': {\n",
+       "    'deps': ['jquery', 'jqueryui']\n",
+       "  },\n",
+       "  'chosen': {\n",
+       "    'deps': ['jquery'],\n",
+       "    'exports': 'jQuery.fn.chosen'\n",
+       "  },\n",
+       "  'contextmenu' : {\n",
+       "    'deps': ['jquery', 'jqueryui', 'position']\n",
+       "  },\n",
+       "  'filesaver' : {\n",
+       "    'deps': ['blob']\n",
+       "  },\n",
+       "  'orbitcontrols': {\n",
+       "    'deps': ['three']\n",
+       "  },\n",
+       "'slickcore': ['jqueryui'],\n",
+       "'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',\n",
+       "              'slickeditors']\n",
+       "}\n",
+       "});\n",
+       "\n",
+       "requirejs(\n",
+       "[\"jquery\", \"model\", \"controller\"],\n",
+       "function($, model, EmperorController) {\n",
+       "  var DecompositionModel = model.DecompositionModel;\n",
+       "\n",
+       "  var div = $('#emperor-notebook-0x4b24c820');\n",
+       "\n",
+       "  var ids = ['232.M3Rkey217', '232.M9Thmr217', '232.M9Pinr217', '232.M3Rinr217', '232.M2Enter217', '232.M9Ekey217', '232.M3Midr217', '232.M3Tkey217', '232.M2Rsft217', '232.M2Okey217', '232.M3Ckey217', '232.M9Akey217', '232.M9Hkey217', '232.M9Pinl217', '232.M2Kkey217', '232.M9Midl217', '232.M9Rinl217', '232.M9Ckey217', '232.M2Midr217', '232.M2Lsft217', '232.M9Mkey217', '232.M9Enter217', '232.M9Bkey217', '232.M9Fkey217', '232.M2Mkey217', '232.M3Wkey217', '232.M9Gkey217', '232.M3Mid [...]
+       "  var coords = [[-0.15847722181174662, -0.17073904878616603, -0.09906305119186608, 0.026134878685267784, 0.06376486684566962], [-0.16364986560249942, 0.16054696199780816, -0.1705790982632183, -0.05197318273194283, -0.011532543354058317], [-0.15600437955361796, 0.17817363880030943, -0.11243701625055075, 0.05400515113780437, -0.07158538372733535], [-0.08793208903635144, -0.21150279045474904, -0.0912521129842712, 0.027392142207187206, -0.1168078281339687], [0.2713433332622112, -0.01 [...]
+       "  var pct_var = [23.330988966275164, 7.445584042747666, 4.615896035685128, 3.4824013326861176, 2.5304874508573096];\n",
+       "  var md_headers = ['SampleID', 'BarcodeSequence', 'LinkerPrimerSequence', 'center_name', 'center_project_name', 'emp_status', 'experiment_design_description', 'key_seq', 'library_construction_protocol', 'linker', 'platform', 'region', 'run_center', 'run_date', 'run_prefix', 'samp_size', 'sample_center', 'sequencing_meth', 'study_center', 'target_gene', 'target_subfragment', 'age', 'age_unit', 'altitude', 'anonymized_name', 'assigned_from_geo', 'body_habitat', 'body_product', 'bo [...]
+       "  var metadata = [['232.M3Rkey217', 'AGTCCATAGCTG', 'CATGCTGCCTCCCGTAGGAGT', 'CCME', 'Forensic_identification_using_skin_bacterial_communities', 'EMP', 'Forensic_identification_using_skin_bacterial_communities', 'TCAG', '16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_thos [...]
+       "  var axesNames = [0, 1, 2, 3, 4];\n",
+       "\n",
+       "  var dm, ec;\n",
+       "\n",
+       "  function init() {\n",
+       "    // Initialize the DecompositionModel\n",
+       "    dm = new DecompositionModel(name, ids, coords, pct_var,\n",
+       "                                md_headers, metadata, axesNames);\n",
+       "    // Initialize the EmperorController\n",
+       "    ec = new EmperorController(dm, 'emperor-notebook-0x4b24c820');\n",
+       "  }\n",
+       "\n",
+       "  function animate() {\n",
+       "    requestAnimationFrame(animate);\n",
+       "    ec.render();\n",
+       "  }\n",
+       "  $(window).resize(function() {\n",
+       "    ec.resize(div.innerWidth(), div.innerHeight());\n",
+       "  });\n",
+       "\n",
+       "  $(function(){\n",
+       "    init();\n",
+       "    animate();\n",
+       "\n",
+       "  });\n",
+       "\n",
+       "}); // END REQUIRE.JS block\n",
+       "</script>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<emperor.core.Emperor at 0x10654efd0>"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "x"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  },
+  "widgets": {
+   "state": {},
+   "version": "1.1.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/keyboard/mapping-file.txt b/examples/keyboard/mapping-file.txt
new file mode 100644
index 0000000..4d53ae0
--- /dev/null
+++ b/examples/keyboard/mapping-file.txt
@@ -0,0 +1,116 @@
+#SampleID	BarcodeSequence	LinkerPrimerSequence	center_name	center_project_name	emp_status	experiment_design_description	key_seq	library_construction_protocol	linker	platform	region	run_center	run_date	run_prefix	samp_size	sample_center	sequencing_meth	study_center	target_gene	target_subfragment	age	age_unit	altitude	anonymized_name	assigned_from_geo	body_habitat	body_product	body_site	collection_timestamp	country	depth	dna_extracted	elevation	env_biome	env_feature	env_matter	has_physical [...]
+232.F10Space217	ATCGCTCGAGGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or [...]
+232.F11Space217	ATCTACTACACG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or [...]
+232.F12Space217	ATCTGGTGCTAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or [...]
+232.L1Space217	ATGCAGCTCAGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.L3Space217	ATGCGTAGTGCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M10Space217	ATCGCGGACGAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or [...]
+232.M11Space217	ATCGTACAACTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or [...]
+232.M2Akey217	ACATGATCGTTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Bkey217	ACGCGATACTGG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Ckey217	ACGATGCGACCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Dkey217	ACATTCAGCGCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Ekey217	ACACTGTTCATG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Enter217	ACGGTGAGTGTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M2Fkey217	ACCACATACATC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Gkey217	ACCAGACGATGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Hkey217	ACCAGCGACTAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Ikey217	ACAGTGCTTCAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Indl217	AACTCGTCGATG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Indr217	AATCGTGACTCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Jkey217	ACCGCAGAGTCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Kkey217	ACCTCGATCAGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Lkey217	ACCTGTCTCTCT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Lsft217	ACGGATCGTCAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Midl217	AACTGTGCGTAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Midr217	ACACACTATGGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Mkey217	ACGCTATCTGGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Nkey217	ACGCGCAGATAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Okey217	ACAGTTGCGCGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Pinl217	AAGCTGCAGTCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Pinr217	ACACGAGCCACA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Pkey217	ACATCACTTAGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Qkey217	ACACGGTGTCTA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Rinl217	AAGAGATGTCGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Rinr217	ACACATGTCTAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Rkey217	ACAGACCACTCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Rsft217	ACGCTCATGGAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Skey217	ACATGTCACGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Space217	ACGTACTCAGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M2Thml217	AACGCACGCTAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Thmr217	AATCAGTCTCGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Tkey217	ACAGAGTCGGCT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Ukey217	ACAGCTAGCTTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Vkey217	ACGCAACTGCTA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Wkey217	ACACTAGATCCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Xkey217	ACGAGTGCTATC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Ykey217	ACAGCAGTGGTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M2Zkey217	ACGACGTCTTAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Akey217	AGTGTTCGATCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Bkey217	ATATGCCAGTGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Ckey217	ATAGGCGATCTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Ekey217	AGTCACATCACT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Gkey217	ATAATCTCGTCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Hkey217	ATACACGTGGCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Indl217	AGCTATCCACGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Indr217	AGGACGCACTGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Jkey217	ATACAGAGCTCC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Kkey217	ATACGTCTTCGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Lkey217	ATACTATTGCGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Lsft217	ATCAGGCGTGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Midl217	AGCTCCATACAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Midr217	AGGCTACACGAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Mkey217	ATCACTAGTCAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Nkey217	ATCACGTAGCGG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Pinl217	AGCTGACTAGTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Pinr217	AGTACGCTCGAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Pkey217	AGTGTCACGGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Qkey217	AGTACTGCAGGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Rinl217	AGCTCTCAGAGG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Rinr217	AGGTGTGATCGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Rkey217	AGTCCATAGCTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Rsft217	ATCCGATCACAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Space217	ATCGATCTGTGG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M3Thml217	AGCGTAGGTCGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Thmr217	AGCTTGACAGCT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Tkey217	AGTCTACTCTGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Vkey217	ATATCGCTACTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Wkey217	AGTAGTATCCTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Xkey217	ATAGCTCCATAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Ykey217	AGTCTCGCATAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M3Zkey217	ATACTCACTCAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Akey217	AGACCGTCAGAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Bkey217	AGCAGCACTTGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Ckey217	AGCACACCTACA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Dkey217	AGACTGCGTACT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Ekey217	ACTCTTCTAGAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Enter217	AGCGAGCTATCT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M9Fkey217	AGAGAGCAAGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Gkey217	AGAGCAAGAGCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Hkey217	AGAGTAGCTAAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Indl217	ACGTGAGAGAAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Indr217	ACTAGCTCCATA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Kkey217	AGATACACGCGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Midl217	ACGTGCCGTAGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Midr217	ACTATTGTCACG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Mkey217	AGCATATGAGAG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Nkey217	AGCAGTCGCGAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Okey217	ACTTGTAGCAGC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Pinl217	ACTACAGCCTAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Pinr217	ACTCAGATACTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Pkey217	AGAACACGTCTC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Qkey217	ACTCGATTCGAT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Rinl217	ACGTTAGCACAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Rinr217	ACTCACGGTATG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Skey217	AGACGTGCACTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Space217	AGCGCTGATGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.M9Thml217	ACGTCTGTAGCA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Thmr217	ACTACGTGTGGT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Vkey217	AGCACGAGCCTA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Wkey217	ACTCGCACAGGA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Xkey217	AGATGTTCTGCT	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.M9Ykey217	ACTGTACGCGTA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_i [...]
+232.R1Space217	ATCTCTGGCATA	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.U1Space217	ATGACCATCGTG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.U2Space217	ATGACTCATTCG	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
+232.U3Space217	ATGAGACTCCAC	CATGCTGCCTCCCGTAGGAGT	CCME	Forensic_identification_using_skin_bacterial_communities	EMP	Forensic_identification_using_skin_bacterial_communities	TCAG	16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_those_with_uncorrectable_barcodes,_ambiguous_bases,_or_ [...]
diff --git a/examples/keyboard/otu-table.biom b/examples/keyboard/otu-table.biom
new file mode 100644
index 0000000..48f7f8b
Binary files /dev/null and b/examples/keyboard/otu-table.biom differ
diff --git a/examples/keyboard/unweighted-unifrac.even1000.txt b/examples/keyboard/unweighted-unifrac.even1000.txt
new file mode 100644
index 0000000..d43db49
--- /dev/null
+++ b/examples/keyboard/unweighted-unifrac.even1000.txt
@@ -0,0 +1,90 @@
+Eigvals	77
+3.833357936551307	1.2233338554050692	0.75840684371616	0.5721699498553411	0.41576737990442836	0.4043128992134731	0.3743825927246075	0.34614463116099997	0.32242615504108907	0.3011944072399825	0.2800690517177874	0.2604444121971143	0.25843242622781887	0.2412755293385157	0.2393272531029426	0.22226990839155011	0.217640301691133	0.20825530057367733	0.1979454994921379	0.19295470901205083	0.18697489224537261	0.18455367632222885	0.18259989446823033	0.1750635371444638	0.16868518671044389	0.16706663 [...]
+
+Proportion explained	77
+0.23330988966275165	0.07445584042747666	0.046158960356851284	0.03482401332686118	0.025304874508573095	0.02460771977625108	0.02278606977119784	0.021067421054915065	0.01962384204713697	0.018331612931355507	0.017045859175105992	0.015851443585165364	0.015728987964722666	0.014684766739767159	0.014566188688596946	0.01352802651370367	0.013246254488671226	0.012675054613407746	0.01204756858351123	0.011743813808843205	0.011379863869096039	0.01123250126189151	0.011113588121943099	0.0106549023626766 [...]
+
+Species	0	0
+
+Site	77	77
+232.M3Rkey217	-0.15847722181174662	-0.17073904878616603	-0.09906305119186608	0.026134878685267784	0.06376486684566962	-0.02624615264949373	2.9528717360592907e-05	0.03751511606176469	0.05654957943663986	0.013267645110691331	0.015118478527396891	0.02332120920027358	-0.07547296587801325	0.011870107612826787	0.07021636397720044	0.008583763680884399	0.04961668107822453	0.10770034774628615	-0.04590183541428798	-0.04849435694610736	-0.045302599327574584	0.013404880237905495	0.015609992504027163 [...]
+232.M9Thmr217	-0.16364986560249942	0.16054696199780816	-0.1705790982632183	-0.05197318273194283	-0.011532543354058317	0.008670864940884706	-0.0399604146988027	0.034494685417307276	-0.03328150646613185	-0.05270044278838983	-0.06954422413189419	0.04735592337890885	-0.07132202338699518	-0.06607976564755952	0.003261434344279651	0.017748801029424156	0.002693458990364364	0.00012465176992220632	0.058087824111357274	-0.050015990825898325	-0.03023259082695939	-0.010957799279368812	0.0191117317536 [...]
+232.M9Pinr217	-0.15600437955361796	0.17817363880030943	-0.11243701625055075	0.05400515113780437	-0.07158538372733535	0.07229132638673622	-0.02236315752354887	0.028380967411194318	-0.053120686643502064	-0.017969346481859046	0.04520884171571392	-0.13334739940451215	0.06047801100694572	0.0323415861488121	-0.01389190496274368	-0.010717967409644182	-0.05857482788432406	0.062290882738703764	0.0017885581149532362	-0.08251223081266222	-0.07184283934956173	0.03619509050682082	0.017825992460654968 [...]
+232.M3Rinr217	-0.08793208903635144	-0.21150279045474904	-0.0912521129842712	0.027392142207187206	-0.1168078281339687	-0.044583743326401956	-0.00022196131581276565	0.009514821161517795	-0.050460786018366406	0.11000919032554532	0.038072536323179564	-0.014549481049333414	-0.07596788661480292	-0.0025060072759466212	0.13375756851847453	-0.04890884616142137	0.005800620578207086	-0.06107693244553186	0.057273421298398776	0.06624498881477767	-0.011297673753261395	-0.025837845443517804	-0.03446283 [...]
+232.M2Enter217	0.2713433332622112	-0.012638234636494947	-0.029044902189380023	-0.08524856180846827	-0.09552021304468544	-0.03633823184470014	-0.0423298240334677	-0.014353594045337564	0.04872683689714746	0.07575592224771899	0.000682722661011643	-0.03259000192568432	-0.0020165328524181475	-0.07991608417780717	-0.05147748115602671	-0.022441444731103766	0.04425892406235187	0.007540627830621387	-0.007414372825228783	-0.08653070737747398	0.058601437167320775	-0.04892068073770706	0.053677461985 [...]
+232.M9Ekey217	-0.19604375771857635	0.06943428720639651	0.1644037396465877	-0.15274462212262158	0.002485811221681098	-0.030231172171822532	0.15106678064830076	0.01164577195071185	-0.10089694662023996	-0.058330761031339794	-0.007169770296485319	0.1011127159075236	-0.04127674340274751	-0.02794559873283723	0.04609330149041218	-0.023327134300987526	-0.03507215864397216	-0.06306730143141809	0.08751210056083115	-0.015510460705539754	0.028824552594343657	-0.06939458319473761	0.008989793060979556 [...]
+232.M3Midr217	-0.12313236193983815	-0.20396253696135883	0.0068688949686654035	0.03245281602572589	-0.12229887273827975	0.11126355802211534	-0.019046120694885357	0.00611499140757858	0.010596346252246378	-0.0926342550197367	0.00462098517075051	0.0816605446660261	-0.02818556046224299	-0.1407665297303425	-0.041453243698556415	-0.15400621437346243	-0.11864521472793763	0.0019370324724592534	-0.010293335641993938	0.015630592776032806	-0.04211579499907383	-0.01781446796885404	0.04669087320151844 [...]
+232.M3Tkey217	-0.18617241853623093	-0.06957738801372167	-0.008329883603523441	0.03351511241361556	0.08363160533038863	0.043489230826882164	0.04931527672443074	0.03911153806131078	0.16807624409500596	-0.06905804467947674	0.08003324149575831	-0.018519236331593976	-0.01632865994134289	-0.00445446579632111	0.014799297680627198	0.009724398195320512	0.05337013389012426	-0.013085070106686686	0.06722512025360984	0.01616422278023989	0.021628848818007296	0.006589961560621183	0.03258979035053096	-0 [...]
+232.M2Rsft217	0.2912046485818605	0.036720642571267476	0.01914945502564694	0.04546272290755183	0.019002166146798685	0.0387671397692785	0.03267425492165029	0.0036029041515630374	0.08240059846336086	0.05979072853858914	-0.026360146102363532	0.08089226261909599	-8.658080192687362e-05	-0.05296521713567387	0.0369203709310347	0.08206876096967669	0.004829002310856715	0.04430232892029738	0.08174642165737384	-7.205652050523326e-05	-0.02944422201993896	0.011094415529703848	0.03660715788534224	-0.03 [...]
+232.M2Okey217	0.18037191232760622	-0.044302059622163215	-0.035074634665129216	-0.13607877379871836	0.007843650881171676	0.09309786934751658	0.06745591550427577	0.06300377903959675	0.007192117705989032	0.0061146098339046814	0.04851988159111851	-0.06745028707264561	0.11797150986540078	0.039003784353721295	0.010265127524034827	0.02025723495391071	0.09087852205453698	0.0426295155321628	0.018249698099774413	-0.06611249094100011	-0.0963148560794182	-0.018763631641435994	-0.07863095355978451	0. [...]
+232.M3Ckey217	-0.20651854409191342	-0.10754641605410008	0.218867181776635	0.02748408650815357	0.08474828402397482	-0.043239224230023215	0.1943207568846395	-0.1656381390691415	0.03604075546647239	-0.014975153299079816	0.04671394810850522	-0.061162408006612934	0.05422599250460878	0.02256819277854577	-0.11887483917330549	-0.04559685824052105	-0.03058413204591484	0.06159102006213015	-0.06375668342522732	-0.01440688520352948	-0.027407700157315563	-0.05489634722575537	-0.016963489517278402	-0. [...]
+232.M9Akey217	-0.1628901111693042	0.09491828490066438	0.2510642890940943	-0.08062018459183551	-0.04732163718460894	0.2074813508317845	-0.12577672347606986	0.0163025498875382	-0.03125978906846314	-0.09671707940078385	0.10051514732452031	-0.11368403133995779	-0.04658358317391274	-0.017017109483107803	0.019533607426321604	0.06577323627294283	-0.11223246959251174	0.05520301261453589	0.02455662169482159	-0.11168057042898742	0.01898539563869883	0.04600339306677476	0.012056090312963062	-0.08030 [...]
+232.M9Hkey217	-0.22156513545344897	0.1910730168085156	0.0942922444528773	-0.02781978153366029	-0.05051561679811557	-0.054232916977301475	-0.05217695144983934	0.007537596053968612	-0.10009770527177812	0.08284053645907188	-0.038728957301436114	0.05373404422298015	0.003696161690014872	-0.1355868446177026	-0.10959397737639895	0.031176246748544367	0.07838363763356296	-0.025756007363272094	0.030626188906492206	0.042031267833881544	-0.052672312730336256	0.07102567073327191	-0.07737148253730046	 [...]
+232.M9Pinl217	-0.15632485239781546	0.13674859553161825	-0.17788276770383105	0.002239855654937378	-0.042446773920532456	-0.009239131544887993	0.03413756745513544	-0.10022695048857837	-0.07582056719005142	-0.1258760316614809	0.08686361337909979	0.02035939327340843	0.03890372149035073	0.06851615360546766	-0.028349714711961734	0.046261000661985116	-0.005121915232510798	-0.09226209496266037	-0.0185720707309724	-0.024152190386363175	0.035918860197206304	-0.03246856883115939	0.00209543837858162 [...]
+232.M2Kkey217	0.24636297782644334	0.03938363206047184	-0.022578688915348408	-0.07504443813875299	-0.057047076790432825	0.03365242911487816	0.09352048690254242	-0.04147869160299176	0.002165464365709347	0.07064034751333444	0.030878839222271477	-0.06612374479489788	-0.037693265358510086	-0.11315183272706338	-0.02882973892403986	-0.010669590034379626	-0.019493971298873376	0.04674134768414062	0.027282974893499515	-0.021380662924414803	0.06933156412276477	0.05982929886604943	-0.028658668908579 [...]
+232.M9Midl217	-0.19274640579634994	0.13352480685670834	-0.09951928886955352	0.0014905430633917359	0.01639911206400835	0.037271455414991765	0.0012158130898897543	-0.07699853264948718	0.07865655551162742	0.012104217565728508	0.026017161423478236	0.12239415199574963	-0.025953506020408745	0.04931263291986722	0.07157783565240841	-0.10798749972649387	-0.028474678006778092	0.01588173136150939	-0.0241181192080547	-0.004105220593462105	-0.051579651662162426	0.0028006319455912967	0.050724741778521 [...]
+232.M9Rinl217	-0.15637700640926644	0.04472580043499717	-0.1601341137824791	-0.06156126491462396	0.027351972560853456	-0.02944031077990626	-0.057945973567014704	-0.12444885016927504	-0.11830836468943572	-0.01883061695535473	0.12296360377991664	0.0066529449694241105	-0.0038311578210773697	0.07711311089955859	0.09639210357005845	-0.024995979622624773	-0.07524768528655035	-0.01989485481565589	0.09455095752174353	-0.004065135956207373	0.017648835297864745	-0.022247011633361666	-0.036538012254 [...]
+232.M9Ckey217	-0.23708319050357407	0.12539159443825545	0.052639079765370723	-0.019720310439054978	0.018834714982491636	-0.022349814347090508	0.000988761778659075	0.012274920446151596	0.05957587085204014	0.0665188375108767	-0.00802524527319574	0.06050443036626885	-0.043778606365960746	0.1076989771332968	-0.036101491668145524	0.003818033394467979	-0.03527838627930791	0.0022241585978422284	-0.0065006943611837864	0.052982066736877165	0.07303981690809161	-0.00705730723448631	-0.00366267182853 [...]
+232.M2Midr217	0.17669949269481314	0.01684731901755309	-0.1141809834460892	0.019364099652335504	-0.016504939651248298	0.10879731302122006	0.07610626141040386	-0.12752573494906816	-0.07984970243994928	0.051702177084047674	-0.05037581388672066	0.011643657394960483	-0.07722772741364445	0.01420816781001185	-0.06553230186793245	0.03907773846517851	0.02636338344822839	-0.012198194669549089	-0.035083115457013606	-0.0025351557550202597	0.023945736512572202	0.05621422435933717	0.05266647963957101	 [...]
+232.M2Lsft217	0.252505593864388	0.014555331870780876	-0.025572762449383855	-0.06381731788702742	0.020238559338512034	0.05913983240483064	0.04727267962591178	0.006567300898641711	-0.01958995494574836	-0.04652409672075564	-0.04804245902388997	-0.008482142976445188	0.0030905778431035555	0.04721372922854477	-0.021098910239246566	0.05454274826587821	-0.024795710617439223	-0.013664835658692144	-0.03512045714161814	0.042731011708611884	-0.03168123428844297	-0.05690158028423315	-0.01980609077550 [...]
+232.M9Mkey217	-0.2299868224010091	0.10912856284019634	-0.016786017429864828	0.014259995035462603	0.02049310954238161	-0.018692877419300046	0.0036587428750270963	0.03799186166688334	0.018507523231332663	0.06559377818176032	0.011051878297419875	-0.06753229482080621	0.019434530856207617	0.0021946473167884692	-0.015654720654946594	0.05126673507025176	-0.059128039118988306	-0.0596712064686666	0.08310879661952146	0.07558712757180328	-0.07436203852136589	-0.06538035887399016	0.09569674204767549 [...]
+232.M9Enter217	-0.23353442534598845	0.12200627629078384	0.12488628056351879	-0.04265237632833217	-0.026108207472737288	0.010104130789992696	0.06981508167870369	0.08414361553273528	-0.0432675970278584	0.024057280304357446	-0.05552732820216846	0.02032395359112072	0.03961597780048578	-0.0429980107124146	-0.0580017245064695	0.02533333854835462	-0.0013842850388022612	-0.01332301742470912	0.03039052977467911	-0.04220419372965383	-0.02605988865413704	0.10806560751850965	0.021688385773084948	0.0 [...]
+232.M9Bkey217	-0.24399001271503873	0.13994050162090302	0.039048592190188754	-0.01659881901675978	0.040857596629480776	-0.03551861849746016	-0.005166811524953147	0.11976569706980551	0.00645030808134298	-0.020187152166404633	0.07009286668568744	0.002624465985816972	-0.0239810005479931	0.010716069314188673	-0.056592043237238474	0.08952812721258178	0.07696869862416408	0.048210948408516446	-0.04581635490345184	0.054265706409994605	0.023336168688569664	0.00442726373239306	0.06783971065100416	- [...]
+232.M9Fkey217	-0.23225540782105822	0.12148858347242074	0.04784053875093525	-0.07110629856735963	0.11927669267344856	-0.10112472472683058	-0.09096354238906097	0.012693152789857864	-0.050239440974548764	0.05179036551651414	0.03432303763222439	0.010265675578558772	0.05795094887398601	-0.054388295886413036	0.04770098925818733	0.042063066348368316	0.07108778147984306	0.028208126401170538	-0.11984020792095618	0.10067491036392988	0.006100949177776102	-0.06780652266294827	0.061472858266459145	-0 [...]
+232.M2Mkey217	0.1205169559886714	0.008842728496562641	-0.05284919402119804	-0.06258363782930602	0.09020816091377616	0.10941204593496774	0.010855199652122458	0.054819590818853514	0.05614496843926827	0.08313288705976558	-0.10492684883753425	0.019112801855821576	0.006285628303658763	0.0272394440202987	-0.053733810393351934	-0.08587270054035999	-0.09387725592675976	-0.004178595454868618	-0.020574682840117795	0.010940282323579353	0.02608598781532541	0.05491269262387296	-0.018505916189873264	0 [...]
+232.M3Wkey217	-0.1656239356143644	-0.1322681822839339	-0.04854077028296568	0.08945793910806446	0.17584122282114784	-0.09391872250459365	0.0014959852239298883	0.023808416333842196	0.0673659711591569	-0.11923827824401467	0.06757967384471593	0.04207293712334438	-0.02314762325948236	-0.06941854863890486	-0.03413123868494948	0.027968855321285783	0.05158662678218586	-0.052725704390259816	0.04938244241722662	-0.14433361457877067	0.011297039824713459	0.04448747158609576	-0.05489575795409974	-0.0 [...]
+232.M9Gkey217	-0.20134237310614408	0.12379371927269059	0.14562061802939283	-0.06358779738900454	-0.07735334049926629	-0.045450773773458825	0.08744856119340304	0.059862255405985984	0.01510293269113441	0.011975466651629128	-0.0971199182260005	-0.006324088377320633	0.015484390347732847	0.05378093585821731	0.12164478205361563	-0.03285669212349693	-0.028556445779030364	0.0878917777001758	-0.013888469159043675	0.01095052052702503	0.03764427375291828	0.003053008768362895	0.04005649103277054	-0. [...]
+232.M3Midl217	-0.14648910732595083	-0.053203021985261646	-0.08316485021554348	0.05247722284738077	-0.07717368947137826	0.039214736835168004	-0.0073395018170603855	0.04898925292804884	0.08228286232031877	-0.005386405926113316	-0.07923868166596693	-0.05419349990651921	0.18269303141760518	0.0036585153377604483	-0.01947556246560325	0.07822625016883344	-0.051626254108542935	-0.011739141045296298	-0.04174611944374479	-0.039336252734385624	0.12478226331586569	0.04343129430146456	-0.084997784901 [...]
+232.M3Pinl217	-0.03714165590970512	-0.2161950319359749	-0.06638760744028739	0.06828540018783485	-0.06963083698415126	0.07883613304520944	-0.14411118609873522	0.0118238101904259	-0.11584574162362096	0.07166735088554038	0.07002100524944896	0.07565119265226757	-0.061100616746449773	0.03842284983230775	0.040498119616146695	-0.02787729937501022	-0.009033375725143396	0.0683906448505421	-0.10467057500665992	-0.05482784780246319	0.07407905278390274	0.010289472684480097	0.061979034431130405	0.056 [...]
+232.M9Vkey217	-0.1902254991440429	0.12060992474464073	0.054394178262302646	-0.03495618135599851	-0.016446698495977338	0.04894311786112617	0.0319508635727867	0.11992544172361061	0.0476389553055697	0.03803202450258837	0.030556517331257478	0.0052295269694649475	0.05084941677770213	0.01145573203768118	0.029940174329269584	-0.09333392817489046	0.024334720906231965	-0.021627386175297	0.02660806875772703	0.031093618430183132	0.1385831673288212	-0.0488208742944323	-0.06046303304232276	0.02259666 [...]
+232.M9Wkey217	-0.23056565771535997	0.16378140716513584	0.050111870526429354	0.008056507785298485	-0.004244207422354574	-0.007148015460468324	0.03459259673062359	0.0854825426578943	0.002218342064173383	0.09652928176848141	0.037015196402621964	0.04841325834227541	-0.045373508341539116	-0.028740589225595234	0.014515255770554774	-0.06380798093938721	0.04107589624665822	0.08320106600453417	-0.03443517852140921	-0.014612597723040625	0.03298830559236865	0.05304078233059838	-0.019311816689442922 [...]
+232.M2Tkey217	0.2932617322976969	0.005779119528765214	0.02359815212959581	-0.022609295700845376	0.0614909769277533	0.04403391669805787	-0.06962936664310598	0.04367664088591024	0.04004896340026275	-0.11260599730354987	-0.116594689884623	-0.003097403795131165	-0.02622256258833896	0.08651035043079078	0.03474975950577062	0.004088970471527731	0.024355595600141652	-0.004872760878179003	-0.030474998493532322	0.038884691069678796	0.0037542749474786057	-0.040277814083077366	-0.0014322261420349899 [...]
+232.M3Indl217	-0.18496001307898863	-0.06631101902657956	-0.10321713059567886	0.055866628535363685	0.08244778557528952	-0.0258805495755417	-0.10116725086045415	-0.01356455957969525	0.047401366543133636	-0.028466494995910196	-0.04175679665765475	-0.0034211594822744214	0.05001314782239272	-0.07606599002142407	-0.03452780057872488	0.08847575573359022	-0.04611769192084145	-0.04729129116277671	-0.035052297529437074	0.018466545080090723	0.03263825327430868	-0.04510500717163789	-0.02647309365536 [...]
+232.M9Dkey217	-0.22248369184406577	0.13745374526238285	0.08215796787844744	-0.07994396370228411	0.016623006896299374	0.0969054378403309	-0.0881171023533027	-0.11930811027040607	0.09711018547375813	-0.01593911408807444	0.07275133072835191	-0.00999724702417884	0.09195388089241617	-0.09819157476509269	0.0883132445270807	0.0008342734983850837	0.004924183573402285	0.02317145046552461	-0.018580332740060813	0.09361177043334537	-0.05782368086251078	0.029313779107578326	0.05580240136940249	0.0967 [...]
+232.M2Indl217	0.20619448134159513	0.020972261528253572	-0.025616711183721733	0.015561603161059088	0.036383835996830566	0.10715482533534909	0.0823034377688929	-0.07189349524539877	-0.059658450457145976	-0.03361539763710873	-0.10019254131443078	-0.05481895903620016	-0.10443476202410505	-0.02258057691539418	0.016880503167534405	0.09433148516475505	0.05964610030027651	0.07093378636473634	-0.001053816890610056	0.01613845814713117	0.10322192157607406	-0.07159431351390451	0.025167145199788264	- [...]
+232.M2Hkey217	0.22216075959328765	-0.021379940144554573	-0.07139324497432455	-0.15480664661929971	0.09426207644864631	-0.013647949690561288	-0.035845397129805105	0.0036769786980311568	-0.042295980519851485	0.031323328684515234	-0.013846566974993472	-0.028075489099795542	0.021052068125616708	0.052565862706423126	-0.032143110668569154	-0.07423095126397261	-0.0726752222160537	0.014156922706773054	-0.009018058931508765	0.051409372231943876	0.005712771290276884	0.04762376211962168	-0.04415470 [...]
+232.M2Gkey217	0.3045123893465498	0.010779208180364952	-0.10609847305401054	-0.03372041772852855	0.026999691378741877	-0.07950900293523501	-0.005964288285172873	-0.04045459189826584	-0.08282367454243919	-0.037867374354871	0.008851492861949351	-0.02947220948459058	-0.0759825378914619	-0.09185389148456283	0.01877900488308205	0.020189287611795278	0.019593158055391136	-0.034202981282648204	-0.08144210239945214	0.013056977696933484	-0.021774156740479937	0.056695804810708204	-0.0134643611560279 [...]
+232.M2Jkey217	0.22450087194943907	-0.06920080239473857	-0.04154374584593726	-0.21041213670486475	0.09770947788503156	0.019142551399209264	-0.02765569188458367	0.06349801232597845	-0.005578386622915362	-0.037172353452325044	0.010615221090825092	-0.05082374658605017	0.030926036141176887	0.024784978552096302	0.023394491120839897	-0.028440796962211905	6.206073594269424e-05	-0.0509593756142373	-0.037623807126630195	0.02988507685490029	-0.023992689399896308	0.01142174371042247	-0.0354518369257 [...]
+232.M9Nkey217	-0.25564311281172614	0.10930395417653681	0.17174199676593258	-0.06852373874093186	-0.05921030657274124	-0.06845269086957895	0.023854470297768975	0.0023061962627483686	-0.04543560599958604	-0.07736039356428641	-0.19787896105312874	0.032577698047183135	-0.04966661221132733	0.04368617491393494	0.025118268371412462	-0.019502079516870018	-0.02467512327466391	-0.013795126927654496	0.041559672829572604	-0.06842355030436399	-0.07298172523043174	-0.03357049296301901	-0.0072021493498 [...]
+232.M2Ukey217	0.170973405832797	-0.017337262074115616	-0.055907798564627464	-0.0806158408279561	-0.007761858828594522	0.05563918874008749	0.011290906241189667	0.038133861258129516	0.05695376573110632	0.002945991616394104	-0.10788787903474122	0.0096172144558194	-0.048919109147886594	-0.049936176502007545	0.08998854410857751	0.062890992056157	-0.05766638802275453	-0.08826588010626085	-0.09916967366052114	0.04446056951807798	-0.038873411645012346	0.09153539104665719	-0.06170378686115632	-0. [...]
+232.M2Fkey217	0.3510265980241152	-0.0035754568645139026	-0.03463408369370149	-0.057047878090560354	-0.03779423682265439	-0.14162039440248833	-0.034776349417504286	-0.03973522021215852	-0.03407342134762779	-0.023602359174347783	0.04135584539539747	-0.02672811449753035	0.010518468492171603	-0.049011674826340994	0.005130339875915999	-0.03415117687404054	0.02260989300507239	0.06296845264926362	0.012357389860648058	-0.025995112029012925	0.024998376296260713	0.07218431296059233	0.0072645513335 [...]
+232.M3Lkey217	-0.12640116000168067	-0.22190603417648808	0.022473611719251222	-0.022616459823228185	0.056162563013940826	0.011571791890328705	-0.13497970054372024	0.12792347206307983	-0.025892669044782893	0.03678126355925817	-0.014603651652074907	-0.04061613522363483	-0.030574793229565553	0.014681220619026224	-0.0623255817341771	-0.004618035273955888	0.036421494815177397	-0.030594644059506838	0.12289961176838499	0.052423321790680516	0.041724891376298395	-0.022636240716721216	-0.0343926003 [...]
+232.M9Pkey217	-0.2356419201628681	0.0330190991009863	0.27903880986898916	-0.07191905264474356	-0.050245651086384596	0.0713547906224927	-0.21543619981107406	-0.21942913339674566	0.09807297301744078	0.0007499399251254243	0.007547506905968846	-0.06615899025642763	-0.12780949909630532	0.07838242343055954	-0.04879704422003118	-0.000774346771386888	0.08872291220542074	-0.07848759638490367	-0.03423560268090806	0.020269171408755064	-0.022370787087285987	-0.008323479972618689	-0.09412617876217516 [...]
+232.M2Ykey217	0.24366473711297643	-0.08079562088851543	-0.006921522626784851	-0.13821744177813852	0.07250627410032398	-0.05391420216810243	-0.028607388589760505	0.004051925685039835	0.0027559501135622335	0.0010325433430098834	0.04589991516241219	0.015598239430807603	-0.014248441676470923	0.06333443641284163	-0.026525438331060195	-0.00022415430034263497	-0.08883777242759283	-0.053562600766988995	0.0009183603654869199	0.024025530372671595	0.07120202115522178	0.07140217368732078	0.024321282 [...]
+232.M2Pinr217	0.18011171788687969	0.015402979870742106	-0.008802803373167857	-0.059246777985413876	0.04331361203637086	0.13833473641843702	0.06673165616164171	-0.044181092671563005	-0.0006669932873409241	0.047564976120220724	0.06643578321845559	0.04363767891679039	0.04143869454818135	0.022527210043739736	-0.0495639233767302	-0.01851282639900767	0.09058156966098645	-0.051395656353249546	0.05906896516141477	-0.012459327224779299	0.054949915862774944	0.024788275218766736	0.06655196686393766 [...]
+232.M2Ikey217	0.2456872562763719	-0.03990324822298844	0.08812051379482759	-0.006819929388620808	-0.10991740062911624	-0.007324085949083984	0.030563613629830493	0.015724078335713453	0.0003189297643396743	0.18044752187798543	0.09352082004022197	0.10029300615933559	0.06521817717051118	0.0674277212545242	0.05316379079586849	0.13280663808065257	-0.06329632932827818	-0.07230996029717197	-0.09754094443505039	-0.10567370930190811	-0.10362163333240207	-0.07370737810076455	-0.03397877783007658	-0. [...]
+232.M2Ekey217	0.3682977847298556	0.0478649521580663	0.09361564634579024	0.13641616128871284	-0.09010041988752744	-0.10078534796557206	-0.07321385432258451	-0.004988277078191227	0.07148155897825678	-0.04863927722477732	-0.017824256272847318	0.03199228820995102	0.0074503596103213995	0.025026265505749382	0.06372776747336246	0.09144489442642116	-0.058768820958545444	0.09357732605771764	0.07005984580319295	0.025446224574922998	0.027594588557283233	0.026616112035994406	-0.0528733010753488	0.00 [...]
+232.M9Midr217	-0.1938926607580852	0.18795460031719471	-0.21344090611199154	0.038255206386736886	-0.03350014110061574	-0.07298016877281742	-0.013020454248638558	-0.016298456872429878	-0.00806368571123371	-0.03694002394011507	0.009348569166557	-0.01625277502024819	0.015573135834988452	0.07323464910001279	0.011505072992094894	0.00020855393565669038	0.006025599861693161	0.02608435524589933	0.0028660823937578365	-0.021662976327645234	-0.016254762050200433	0.017827161802711537	-0.0127914265413 [...]
+232.M3Space217	-0.19168900554321885	-0.22152353374792114	0.07143975501040269	-0.019697446299004825	-0.031371503561151474	-0.08962261893594349	-0.028168903047505866	-0.09100279268548744	-0.07804504645746267	0.057769584858025656	-0.152040606996419	0.01845062851230934	0.15648297056857835	0.053288896691250844	0.005982783830513774	-0.001367254509701113	0.050082030675186504	-0.011968621330229705	-0.009285700271633958	-0.03663898037638591	-0.016204582452470074	0.0589350187302376	0.0536858233554 [...]
+232.M9Thml217	-0.23930798006082651	0.2504407788032832	-0.07460899236970182	0.03406020007750262	-0.02438830654821116	-0.07059213268102274	0.009081540545407968	0.047630256900355675	-0.01738238083547873	-0.01700463488557365	0.0321427656948681	0.029248404680259483	0.00957850497383571	0.01281319661436027	-0.027497264645601562	-0.012359177641051688	0.023708389807965354	-0.0363317710543422	-0.04405121311682134	0.002483654784492699	0.06592539471506942	-0.039663131133882555	-0.014651227114996022	 [...]
+232.M9Rinr217	-0.16309261567340014	0.21115256111857691	-0.2262520932666264	0.046969186685865895	-0.038170277484061876	0.009481862020609265	-0.018765454537527645	-0.037531258825238924	0.0651991777312134	-0.027936850919784036	-0.01393749027537664	-0.005473093541720845	0.0030283977283421843	-0.03742328528298582	-0.03412264754977898	-0.0018342748031099291	0.01891588347893822	0.014686392729192985	-0.024134924403193706	-0.008782783866132888	-0.02843125412048011	-0.014525250578130828	-0.0347823 [...]
+232.M3Mkey217	-0.14948783606594587	-0.21192638374223463	0.13819037969707026	-0.04756247990395532	0.06062861033979177	-0.04323542700875117	0.034612037105374985	0.08376712998823528	-0.1854518936844697	-0.06872559568656506	0.055724569909480326	-0.03675351712252605	-0.03231086750741767	-0.0490345748802314	0.0028829324034354317	0.05846468735104851	-0.04232040473562526	0.0715661826520999	-0.09801472587176714	0.03782016890515008	0.011584693923454755	-0.019690561430604662	-0.005072399566701261	0 [...]
+232.M3Rsft217	-0.1293675874962787	-0.12928819044216355	-0.010541797652542373	0.04687797406468326	-0.1384684923654932	0.0020857038154609257	0.08774295864556496	0.06133037677241845	0.038537068904677105	0.022510917892433285	0.02001792715762569	-0.17366193164035212	-0.0455633659727248	-0.02987252845983012	0.1435146616122457	0.01782063527334964	0.08865834215865644	-0.14684363049102153	0.012021043814459129	0.028917408549620254	-0.015362680787792042	0.05615223878197316	0.06144570273314773	0.084 [...]
+232.M2Lkey217	0.1853715242266962	-0.04394076376577986	0.0013957413384741062	-0.08713319689971091	0.11051971956688506	0.02405142051199587	-0.07602894628593913	0.07748512171993331	-0.027387721380347136	0.02336810293608099	0.050585841439513675	0.05882972063207756	0.1120041336263198	0.020061496220746745	0.049112062301200146	-0.06305465501535787	0.07990528331080866	0.060253290438422945	0.04518520524734879	-0.019470425341077	-0.050872917888447215	-0.02465014542305482	-0.07759974423072467	-0.01 [...]
+232.M2Space217	0.35223305849195774	-0.02617411803865043	-0.0035699117340603414	-0.09720392816850307	-0.08807674165704805	-0.10768151362369925	-0.02378847803058605	0.004849617712946737	0.037004728520474484	0.0058068236383046375	0.020354144269068185	-0.007131801063192769	-0.018174395213726012	-0.03821892381493336	-0.037179523550822685	-0.009877137879256148	0.008516556994140905	0.007900645444093012	0.027194213165292153	-0.015059023131665508	0.021611589147845653	-0.06234240042808286	0.051305 [...]
+232.M2Vkey217	0.3657428302603664	0.02398432130768629	-0.009965214758798897	-0.02440104170499919	-0.009946510063913857	-0.04685501407143239	0.023674089735483298	-0.01992498962553938	0.024763053017740885	-0.04425517493072748	0.01469414215558826	0.03074750075648138	-0.045362242888448055	-0.034694823505325496	-0.014777903769787493	-0.01051524942393438	0.0040687063683504795	-0.0069152990655214725	-0.01810187198151043	0.04953543642189357	-0.025493392445605174	-0.008139849720974372	-0.008278120 [...]
+232.M3Gkey217	-0.1306513653138075	-0.12255623486647205	-0.06423217213467512	0.016758606503725536	0.16845698607059986	-0.0033334408823929335	-0.018885769014578203	0.011363370137291003	0.036429986322756486	0.05264558900135169	-0.07928806993698347	-0.058013158961847444	-0.09049417388854633	-0.034930528926037874	0.03376835403700971	-0.016152986283282204	-0.016437458909967038	0.09821723230726889	0.03614758555917968	-0.0724377911296033	-0.07074584014436476	-0.07420949172971128	-0.0067887166575 [...]
+232.M9Indr217	-0.19927266681288283	0.20920906228393868	-0.1697924444420701	0.028979324365290042	-0.046242263775499094	-0.015719202171027086	-0.010383993455106494	-0.005891797585881426	0.01779086797531729	0.011584343726103388	-0.06584871920761376	-0.006421356128226143	-0.023332809321174743	0.006932889224487514	-0.02095499614727632	-0.02570973117504009	0.011782872114962532	0.01793163681209444	-0.03188687046867544	-0.012104527618081458	-0.008232360737775163	-0.021715657162935866	-0.03693360 [...]
+232.M3Xkey217	-0.12496946972727718	-0.22187532285360786	-0.06751711214893302	-0.004956783891719452	-0.05859899402568845	0.024636332171870758	0.1119526807649808	-0.01648253465135609	0.06353941914779385	-0.004681561215954319	0.0332180875262765	0.02407293762701984	-0.07602046155181286	0.0900821754901243	-0.0442392787361485	-2.32025648977949e-05	0.0361977151414843	0.08034172857866183	-0.03496545840794273	0.0579986533271565	-0.02126362560638242	0.017494133260708478	-0.04895935618896669	0.0387 [...]
+232.M3Ykey217	-0.16029002821260424	-0.16435051448056975	0.004489617087366096	-0.04065527088625365	-0.07342478249812615	-0.016822247626364386	0.17687112737249172	-0.06697653767525309	0.02471838845075336	-0.06911612748135999	0.029143350334415934	0.04547160345586113	0.04251809083770133	-0.03312644956640603	0.06298890329760441	0.010351987230052826	-0.022425020496959533	-0.014067885826767225	-0.011942171906898958	0.01463449670235676	0.07366978182041846	-0.015640367935408465	-0.067699374327195 [...]
+232.M3Vkey217	-0.1999446986079944	-0.11197931719829385	0.05614128595392682	0.056712510058803456	0.12544482964194237	-0.08765594596838984	0.028080732258413864	-0.2070025396563064	0.054268903368544716	0.05315655692718526	-0.03062603735884373	0.0254115773780789	0.05232926038227096	-0.05274237729104898	0.05870235961304708	-0.038125514714142245	0.01825372974047599	0.007118177725781476	0.013644305347031706	-0.016715495119896118	0.022967212653653455	0.09623289431985248	-0.007517500012528326	-0. [...]
+232.M2Bkey217	0.3155976418651947	0.06181751810464016	-0.03983658891207111	-0.019480623503277786	0.025521482991186763	0.012214606051096031	0.037262015017853665	-0.02711167337665737	-0.03369482195841253	-0.06099482960735397	-0.01967564354584564	0.007167305279672216	0.0008816948921581701	0.05454218242135586	-0.08082538411844689	-0.039908807197025865	-0.013203711112261892	-0.000504735886797687	0.036702425383623935	0.03858789734096821	-0.0768501387517421	-0.005911161709484209	0.02153287239808 [...]
+232.M3Pinr217	-0.13673609373804937	-0.23186848427230336	-0.024311609113230385	0.041388191695546674	-0.17416805194930957	0.027580310935685796	0.016438206656517414	0.03564043463757204	-0.01892117029459698	-0.10965325931177798	-0.029943794441797136	-0.005545699596210342	0.013649379000457207	0.10701639624215938	-0.02773764105991572	-0.008923392829224094	0.15069795984929105	0.05194853076110887	0.02905146689389658	0.034278716016906345	-0.043404669677134265	0.036738736962668994	0.00452997853523 [...]
+232.M3Bkey217	-0.18141765530423826	-0.1059983575557922	-0.01229614981853032	0.08254603932784547	0.1392329897856232	-0.09457771746265621	0.04120302994553591	0.02991416861848655	0.031231323593091866	-0.05184666367303153	-0.02310597953304552	-0.10543095657364396	0.014489156765134587	0.017821445226935823	0.043054534550699276	0.01669931227944315	-0.09713558892043668	-0.05318783865168463	-0.01045374085797102	-0.012809604215807634	-0.012434333268965791	0.01570667330712608	0.08518563156968889	0. [...]
+232.M2Akey217	0.3317327175964213	0.031494188522948004	0.003731619268066509	0.02465980933022621	-3.0439093436323844e-05	-0.03786233262842006	-0.02169967308687759	-0.008993082715140523	0.04712252437421472	-0.027257628675212003	-0.049326892909783246	0.00884628673869111	0.025223790472983537	0.060344188935325734	-0.027981281812834127	0.044196386711432174	0.018878603053429824	0.024897222872321878	-0.014962385988856866	0.001598582550132477	0.011984674587616598	0.013209117420412673	0.11260841005 [...]
+232.M3Indr217	-0.10621826956644516	-0.25131819509746434	-0.014896748387920242	0.04345134189355944	-0.038575710784660336	0.04327256686761698	-0.12285728722281263	-0.019489545034743247	-0.12756725567978278	-0.09519677556380121	-0.06997847771240123	0.10713630949330487	0.08654222679299318	-0.0494984782106446	-0.01918744444234258	0.006522090642121726	0.02735314111284632	-0.031610507884099845	0.02137978399593517	-0.008249367249613856	0.024365990999984974	-0.041749856215594676	0.002801184697799 [...]
+232.M3Thmr217	-0.14129602772271763	-0.1756429547567575	-0.07199362277576048	0.09748286091573695	-0.11137468562433617	0.08713852273379658	-0.012641337589986734	0.01591080392557048	0.06517117094321265	0.01066962929355949	0.016610279981268756	0.007617898821852162	0.08620651012911774	-0.06934223150160894	-0.1035265880954656	0.0002851208881142785	-0.07960612869276193	0.044670262891214424	0.01037192123254821	0.13250404774391542	-0.044948948202106875	-0.05660392028674904	0.0245758167383598	-0.0 [...]
+232.M2Skey217	0.2676657252799645	0.022724293292963778	0.081082933900486	0.13633659095053513	0.04413583207885528	0.0716886295443745	-0.06205588570453921	-0.036512147113594795	0.03980843747446726	0.020839728711545595	0.003244650551214046	0.13649233265049474	0.002139941284177125	0.013758507383235278	0.07529708406225771	0.09896960625921437	-0.023932382330826892	0.014875000986511233	0.08807679729030064	0.008599090552634407	0.023395110916298145	0.009720096928774555	0.002635455598912921	0.01496 [...]
+232.M2Wkey217	0.34420030621006364	0.01839022700771831	0.06662309051527394	-0.022038885202044545	-0.0381067810278206	-0.07120299166138276	-0.029126097013016865	0.010046090604777635	0.009474666175239697	-0.021766441003570624	0.045294404789830885	-0.012714479392108841	0.032413651116454625	0.06435574167832404	-0.057950998258502515	-0.03352301251796334	0.003958305850052585	-0.024078231811609892	0.04955137981743294	-0.015127741215958265	0.01904081634988899	0.050912524480371736	0.13230062797370 [...]
+232.M2Rinr217	0.1904330375606542	0.021547297298635325	-0.047426260379625176	-0.00995748336814545	0.06487085248938376	0.14518876407664827	0.11427708919800939	-0.040657061442017875	-0.06142992693407463	0.07600550510452006	-0.0002960597189041317	-0.015569352609696786	0.002558189850501897	-0.05058601219483914	-0.003634980933999493	0.047410406411256885	0.028779876054133825	-0.02197156701550396	0.0454825740584519	0.0009209826791113095	-0.03252506599250045	-0.07454634294377756	-0.03708755780358 [...]
+232.M2Ckey217	0.38895777685685196	0.0808088261048264	0.10129752373641526	0.11044866831795262	-0.07980610441760053	-0.1810438623820791	0.025436685455623276	-0.0031351068968673893	0.010387802369672097	-0.04671912641940832	0.08011281607367751	-0.011867349519354423	-0.016969499026020424	-0.02276027046321768	-0.029999558007082008	0.019169129390566017	-0.03530715847022262	0.05508999646661013	0.02936904192210607	0.0507842698458102	-0.01879129103168838	-0.04367142156149906	-0.08131702328585093	0 [...]
+232.M3Ekey217	-0.19985586324704674	-0.12768336870987695	0.045215825749683164	0.0645140247955815	0.023251974368653117	-0.019869436201578786	0.03193245886960426	0.12130134837186883	0.06348613048527117	0.051220668164727486	0.05849077000856128	0.1042258776267932	-0.11702114556241844	0.05113620733868939	-0.1293795343919207	0.0412211622396791	-0.027727987482186054	-0.09402238346922995	-0.043596915316794806	-0.06309102242359456	-0.040087553363143666	0.028369397448012527	0.009733819616461073	0.0 [...]
+232.M2Zkey217	0.3051909705017922	-0.01371994822117235	0.047361317623258695	-0.04412772222520342	-0.07246043769180281	-0.08791554964553544	-0.07046868081389748	0.017486316305050355	0.1271453799703734	0.007600137726079434	-0.037569305394031596	-0.0568923970830819	0.010007656291787603	-0.05925950730540667	-0.00286036946664524	-0.11567476173585496	0.024025399897792704	-0.06099627816176274	-0.06559972733356294	-0.10885619253446224	0.016651813298235296	-0.13569348778037896	0.02543004618763564	 [...]
+232.M2Thml217	0.299890280724788	0.08977878843297697	0.09116669471839534	0.1892764639789811	0.0022454014974880943	-0.03493542179235677	0.0002492378734605718	0.0725694772438364	-0.036739245450558594	-0.05155184969102758	0.041124234723398295	-0.009152872912670706	-0.009951327106329757	0.010860171914645363	0.009313091371662726	-0.09115310720235487	-0.01287696791126836	-0.03748432890207639	-0.021884649306077666	0.055617525873824666	-0.07246829619193165	0.09748593114684902	-0.06164114572142278 [...]
+232.M2Rinl217	0.22198729527657515	0.12214532788707587	0.11021906264009938	0.2757058013168845	0.09878294657818378	0.08374791066988813	0.018441038522693808	0.011286678736966817	-0.11418581154605227	0.00818880333627535	0.013998239543846974	-0.00988492969032357	0.06240285400454134	-0.012516089315946414	0.03045951874512495	-0.07262525886508747	0.04961653877485827	-0.055049066885584974	-0.034910547766222336	-0.0035389550263586213	-0.025999462848953138	-0.01330167650398004	0.05629597491850345	0 [...]
+232.M3Rinl217	-0.16985599804002258	-0.08194430923815636	-0.038144881316898305	0.10707573904793212	0.011993693727467282	-0.09497036957750678	-0.040519851364508454	-0.0561558687813965	-0.08314145407097039	0.1924520275295758	-0.031519121400645306	-0.13091879562676279	-0.032755711404000576	0.0469316824098859	-0.061818269718399405	0.006809768604358865	-0.06598618669058647	0.020656311492801272	0.0857327407420903	0.009577503793298952	0.007019164566336426	-0.02052392388699418	-0.0209569783795229 [...]
+232.M2Midl217	0.24014814312048188	0.12047536482638979	0.10805125414547544	0.31840658432316493	0.06031581781385022	0.0901076440123498	0.011285443189699653	0.0224454300074865	-0.05544056938039025	0.0011563381428749972	-0.039130950671035225	-0.05190706199196143	-0.012138410435387938	0.018159758051849852	0.02740586254620915	-0.08292745209461494	0.01853315893279754	-0.040073763661270495	-0.04231532744756733	-0.01724725416150758	0.06528714937734603	-0.04016948738023608	-0.05895467490037302	-0. [...]
+
+Biplot	0	0
+
+Site constraints	0	0
diff --git a/examples/scipy-2016.ipynb b/examples/scipy-2016.ipynb
new file mode 100644
index 0000000..29f3a5a
--- /dev/null
+++ b/examples/scipy-2016.ipynb
@@ -0,0 +1,4304 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'start_slideshow_at': 'selected', 'theme': 'serif', 'transition': 'fade'}"
+      ]
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# setup the presentation settings\n",
+    "from notebook.services.config import ConfigManager\n",
+    "cm = ConfigManager()\n",
+    "cm.update('livereveal', {\n",
+    "              'theme': 'serif',\n",
+    "              'start_slideshow_at': 'selected',\n",
+    "              'transition': 'fade'\n",
+    "})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "# some good ol' imports\n",
+    "import pandas as pd, numpy as np\n",
+    "from emperor import Emperor, nbinstall\n",
+    "from skbio import OrdinationResults\n",
+    "\n",
+    "from emperor.qiime_backports.parse import parse_mapping_file\n",
+    "from emperor.qiime_backports.format import format_mapping_file\n",
+    "\n",
+    "from skbio.io.util import open_file\n",
+    "\n",
+    "nbinstall()\n",
+    "\n",
+    "def load_mf(fn):\n",
+    "    with open_file(fn) as f:\n",
+    "        mapping_data, header, _ = parse_mapping_file(f)\n",
+    "        _mapping_file = pd.DataFrame(mapping_data, columns=header)\n",
+    "        _mapping_file.set_index('SampleID', inplace=True)\n",
+    "    return _mapping_file\n",
+    "\n",
+    "def write_mf(f, _df):\n",
+    "    with open(f, 'w') as fp:\n",
+    "        lines = format_mapping_file(['SampleID'] + _df.columns.tolist(),\n",
+    "                                    list(_df.itertuples()))\n",
+    "        fp.write(lines+'\\n')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "def one_more_thing():\n",
+    "    return 'We are hiring, contact robknight at ucsd.edu'"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Emperor: interactive $\\beta$-diversity visualization"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "-"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "# @ElDeveloper on GitHub\n",
+    "__presenter__ = 'Yoshiki Vazquez-Baeza'\n",
+    "__email__ = 'yoshiki at ucsd.edu'\n",
+    "\n",
+    "\n",
+    "__license__ = 'BSD-3'\n",
+    "__url__ = 'https://github.com/biocore/emperor'"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<table style='border:none; width:100%;' cellspacing=\"0\" cellpadding=\"0\">\n",
+    "<tr style='border:none;'>\n",
+    "<td style='border:none;'>\n",
+    "<img src=\"https://upload.wikimedia.org/wikipedia/commons/f/f6/UCSD_logo.png\" alt=\"ucsd\" style=\"height: 50px;\"/>\n",
+    "</td>\n",
+    "<td style='border:none;'>\n",
+    "<img src=\"./images/knight-logo.png\" alt=\"knight-lab\" style=\"height: 100px;\"/>\n",
+    "</td>\n",
+    "</tr>\n",
+    "</table>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- Background (why $\\beta$-diversity).\n",
+    "\n",
+    "- What is Emperor.\n",
+    "\n",
+    "- How can we use Emperor.\n",
+    "    \n",
+    "- Analyzing a use case."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- **Background (why $\\beta$-diversity).**\n",
+    "\n",
+    "- What is Emperor.\n",
+    "\n",
+    "- How can we use Emperor.\n",
+    "    \n",
+    "- Analyzing a use case."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Microscopic worlds on and inside our bodies\n",
+    "\n",
+    "<img src='http://news.nationalgeographic.com/content/dam/news/photos/000/819/81998.ngsversion.1422281191282.adapt.1900.1.jpg' style='height:500px'>\n",
+    "\n",
+    "Photograph by Martin Oeggerli, Micronaut, Supported by School of Life Sciences."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# How do we make sense out of them?\n",
+    "\n",
+    "![microbe](./images/microbes.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# How do we make sense out of them?\n",
+    "\n",
+    "![microbe](./images/microbes-metric.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is $\\beta$-diversity\n",
+    "\n",
+    "- Comparison of two individual communities to determine how similar they are.\n",
+    "\n",
+    "<img src=\"./images/table-2.png\" alt=\"ucsd\" style=\"height: 500px;\"/>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is $\\beta$-diversity\n",
+    "\n",
+    "- Comparison of two individual communities to determine how similar they are.\n",
+    "\n",
+    "<img src=\"./images/distance-matrix.png\" alt=\"dm\"/>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is $\\beta$-diversity\n",
+    "\n",
+    "- Comparison of two individual samples to determine how similar they are.\n",
+    "- Elucidate patterns.\n",
+    "\n",
+    "![costello](./images/costello.png)\n",
+    "\n",
+    "<p><small>\n",
+    "    Bacterial community variation in human body habitats across space and time.\n",
+    "    Costello EK et al. 2009.\n",
+    "</small></p>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is $\\beta$-diversity\n",
+    "\n",
+    "- Comparison of two individual samples to determine how similar they are.\n",
+    "- Elucidate patterns.\n",
+    "\n",
+    "![costello](./images/costello-colored.png)\n",
+    "\n",
+    "<p><small>\n",
+    "    Bacterial community variation in human body habitats across space and time.\n",
+    "    Costello EK et al. 2009.\n",
+    "</small></p>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is $\\beta$-diversity\n",
+    "\n",
+    "- Comparison of two individual samples to determine how similar they are.\n",
+    "- Elucidate patterns.\n",
+    "\n",
+    "![costello](./images/costello-all.png)\n",
+    "\n",
+    "<p><small>\n",
+    "    Bacterial community variation in human body habitats across space and time.\n",
+    "    Costello EK et al. 2009.\n",
+    "</small></p>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "from skbio import OrdinationResults\n",
+    "\n",
+    "coordinates = OrdinationResults.read('costello/unweighted_unifrac_pc.txt')\n",
+    "metadata = load_mf('costello/mapping-file.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfQAAAHWCAYAAACBsnu3AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzsvXecVOW9x/8+08vOLrtLL1IWBFQEBcGKJSq2RKPXmERN\nMzEaYxKN+SU35aZqft6bn16NJVcxRqPGWGOsGI2CAoKIgjTpZSkLbJ8+Z875/TE849lhet/Z5/16\n5aXB4cwzz5k5n+fblbfeektHIpFIJBJJv8ZU6QVIJBKJRCIpHCnoEolEIpHUAFLQJRKJRCKpAaSg\nSyQSiURSA0hBl0gkEomkBpCCLpFIJBJJDSAFXSKRSCSSGkAKukQikUgkNYAUdIlEIpFIagBLti88\n44wzSrgMiUQikUgkyXj77bezep200CUSiUQiqQGkoEskEolEUgNIQZdIJBKJpAaQgi6RSCQSSQ0g\nBV0i [...]
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       "  \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Created with matplotlib (http://matplotlib.org/) -->\n",
+       "<svg height=\"338pt\" version=\"1.1\" viewBox=\"0 0 359 338\" width=\"359pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       " <defs>\n",
+       "  <style type=\"text/css\">\n",
+       "*{stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:100000;}\n",
+       "  </style>\n",
+       " </defs>\n",
+       " <g id=\"figure_1\">\n",
+       "  <g id=\"patch_1\">\n",
+       "   <path d=\"M 0 338.4 \n",
+       "L 360 338.4 \n",
+       "L 360 0 \n",
+       "L 0 0 \n",
+       "z\n",
+       "\" style=\"fill:#bfbfbf;\"/>\n",
+       "  </g>\n",
+       "  <g id=\"patch_2\">\n",
+       "   <path d=\"M 7.2 331.2 \n",
+       "L 352.8 331.2 \n",
+       "L 352.8 7.2 \n",
+       "L 7.2 7.2 \n",
+       "z\n",
+       "\" style=\"fill:#ffffff;\"/>\n",
+       "  </g>\n",
+       "  <g id=\"pane3d_1\">\n",
+       "   <g id=\"patch_3\">\n",
+       "    <path d=\"M 53.01462 259.607418 \n",
+       "L 151.927149 180.16996 \n",
+       "L 150.28036 28.378014 \n",
+       "L 45.85281 99.750937 \n",
+       "\" style=\"fill:#f2f2f2;opacity:0.5;stroke:#f2f2f2;stroke-linejoin:miter;\"/>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"pane3d_2\">\n",
+       "   <g id=\"patch_4\">\n",
+       "    <path d=\"M 151.927149 180.16996 \n",
+       "L 312.156145 224.580625 \n",
+       "L 318.859934 68.211455 \n",
+       "L 150.28036 28.378014 \n",
+       "\" style=\"fill:#e6e6e6;opacity:0.5;stroke:#e6e6e6;stroke-linejoin:miter;\"/>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"pane3d_3\">\n",
+       "   <g id=\"patch_5\">\n",
+       "    <path d=\"M 53.01462 259.607418 \n",
+       "L 221.597175 311.330875 \n",
+       "L 312.156145 224.580625 \n",
+       "L 151.927149 180.16996 \n",
+       "\" style=\"fill:#ececec;opacity:0.5;stroke:#ececec;stroke-linejoin:miter;\"/>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"axis3d_1\">\n",
+       "   <g id=\"line2d_1\">\n",
+       "    <path d=\"M 53.01462 259.607418 \n",
+       "L 221.597175 311.330875 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-width:0.75;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"text_1\">\n",
+       "    <!-- 0 -->\n",
+       "    <defs>\n",
+       "     <path d=\"M 31.78125 66.40625 \n",
+       "Q 24.171875 66.40625 20.328125 58.90625 \n",
+       "Q 16.5 51.421875 16.5 36.375 \n",
+       "Q 16.5 21.390625 20.328125 13.890625 \n",
+       "Q 24.171875 6.390625 31.78125 6.390625 \n",
+       "Q 39.453125 6.390625 43.28125 13.890625 \n",
+       "Q 47.125 21.390625 47.125 36.375 \n",
+       "Q 47.125 51.421875 43.28125 58.90625 \n",
+       "Q 39.453125 66.40625 31.78125 66.40625 \n",
+       "M 31.78125 74.21875 \n",
+       "Q 44.046875 74.21875 50.515625 64.515625 \n",
+       "Q 56.984375 54.828125 56.984375 36.375 \n",
+       "Q 56.984375 17.96875 50.515625 8.265625 \n",
+       "Q 44.046875 -1.421875 31.78125 -1.421875 \n",
+       "Q 19.53125 -1.421875 13.0625 8.265625 \n",
+       "Q 6.59375 17.96875 6.59375 36.375 \n",
+       "Q 6.59375 54.828125 13.0625 64.515625 \n",
+       "Q 19.53125 74.21875 31.78125 74.21875 \n",
+       "\" id=\"BitstreamVeraSans-Roman-30\"/>\n",
+       "    </defs>\n",
+       "    <g transform=\"translate(116.610780547 324.606857811)scale(0.12 -0.12)\">\n",
+       "     <use xlink:href=\"#BitstreamVeraSans-Roman-30\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"Line3DCollection_1\">\n",
+       "    <path d=\"M 73.530439 265.901955 \n",
+       "L 171.483883 185.590499 \n",
+       "L 170.817005 33.230591 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 108.61639 276.666809 \n",
+       "L 204.892601 194.850392 \n",
+       "L 205.924955 41.526201 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 144.38815 287.64208 \n",
+       "L 238.906336 204.277978 \n",
+       "L 241.70146 49.979783 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 180.866026 298.833996 \n",
+       "L 273.541674 213.877854 \n",
+       "L 278.165802 58.595894 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 218.071132 310.249036 \n",
+       "L 308.815811 223.654785 \n",
+       "L 315.33801 67.379265 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_1\">\n",
+       "    <g id=\"line2d_2\">\n",
+       "     <path d=\"M 74.374529 265.209891 \n",
+       "L 71.839102 267.288673 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_2\">\n",
+       "    <g id=\"line2d_3\">\n",
+       "     <path d=\"M 109.446602 275.961288 \n",
+       "L 106.952832 278.080517 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_3\">\n",
+       "    <g id=\"line2d_4\">\n",
+       "     <path d=\"M 145.203778 286.922705 \n",
+       "L 142.753786 289.083573 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_4\">\n",
+       "    <g id=\"line2d_5\">\n",
+       "     <path d=\"M 181.666328 298.100355 \n",
+       "L 179.262338 300.304102 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_5\">\n",
+       "    <g id=\"line2d_6\">\n",
+       "     <path d=\"M 218.855335 309.500701 \n",
+       "L 216.499678 311.748617 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"axis3d_2\">\n",
+       "   <g id=\"line2d_7\">\n",
+       "    <path d=\"M 312.156145 224.580625 \n",
+       "L 221.597175 311.330875 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-width:0.75;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"text_2\">\n",
+       "    <!-- 1 -->\n",
+       "    <defs>\n",
+       "     <path d=\"M 12.40625 8.296875 \n",
+       "L 28.515625 8.296875 \n",
+       "L 28.515625 63.921875 \n",
+       "L 10.984375 60.40625 \n",
+       "L 10.984375 69.390625 \n",
+       "L 28.421875 72.90625 \n",
+       "L 38.28125 72.90625 \n",
+       "L 38.28125 8.296875 \n",
+       "L 54.390625 8.296875 \n",
+       "L 54.390625 0 \n",
+       "L 12.40625 0 \n",
+       "z\n",
+       "\" id=\"BitstreamVeraSans-Roman-31\"/>\n",
+       "    </defs>\n",
+       "    <g transform=\"translate(289.749044878 299.694047875)scale(0.12 -0.12)\">\n",
+       "     <use xlink:href=\"#BitstreamVeraSans-Roman-31\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"Line3DCollection_2\">\n",
+       "    <path d=\"M 48.1081 98.209518 \n",
+       "L 55.142669 257.898365 \n",
+       "L 223.551905 309.458356 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 61.487006 89.065459 \n",
+       "L 67.774108 247.753954 \n",
+       "L 235.148767 298.349235 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 74.609352 80.096752 \n",
+       "L 80.175571 237.794238 \n",
+       "L 246.524817 287.451637 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 87.482447 71.298399 \n",
+       "L 92.353281 228.014219 \n",
+       "L 257.686304 276.759579 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 100.113327 62.665593 \n",
+       "L 104.313242 218.409077 \n",
+       "L 268.63924 266.2673 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 112.508763 54.193704 \n",
+       "L 116.06124 208.974164 \n",
+       "L 279.389417 255.969253 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 124.675279 45.878276 \n",
+       "L 127.602862 199.704993 \n",
+       "L 289.942414 245.860093 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 136.619157 37.715014 \n",
+       "L 138.943497 190.597236 \n",
+       "L 300.303605 235.934672 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 148.346454 29.699778 \n",
+       "L 150.088352 181.646713 \n",
+       "L 310.478174 226.188024 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_6\">\n",
+       "    <g id=\"line2d_8\">\n",
+       "     <path d=\"M 222.142249 309.026778 \n",
+       "L 226.37438 310.322482 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_7\">\n",
+       "    <g id=\"line2d_9\">\n",
+       "     <path d=\"M 233.748366 297.925911 \n",
+       "L 237.952679 299.196823 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_8\">\n",
+       "    <g id=\"line2d_10\">\n",
+       "     <path d=\"M 245.133577 287.036334 \n",
+       "L 249.310359 288.283157 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_9\">\n",
+       "    <g id=\"line2d_11\">\n",
+       "     <path d=\"M 256.304129 276.35207 \n",
+       "L 260.453667 277.575484 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_10\">\n",
+       "    <g id=\"line2d_12\">\n",
+       "     <path d=\"M 267.266036 265.867369 \n",
+       "L 271.388613 267.068026 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_11\">\n",
+       "    <g id=\"line2d_13\">\n",
+       "     <path d=\"M 278.025091 255.57669 \n",
+       "L 282.120989 256.755219 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_12\">\n",
+       "    <g id=\"line2d_14\">\n",
+       "     <path d=\"M 288.586871 245.474696 \n",
+       "L 292.656372 246.631705 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_13\">\n",
+       "    <g id=\"line2d_15\">\n",
+       "     <path d=\"M 298.956754 235.556246 \n",
+       "L 303.000136 236.692318 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_14\">\n",
+       "    <g id=\"line2d_16\">\n",
+       "     <path d=\"M 309.139922 225.816383 \n",
+       "L 313.157462 226.93208 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"axis3d_3\">\n",
+       "   <g id=\"line2d_17\">\n",
+       "    <path d=\"M 312.156145 224.580625 \n",
+       "L 318.859934 68.211455 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-width:0.75;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"text_3\">\n",
+       "    <!-- 2 -->\n",
+       "    <defs>\n",
+       "     <path d=\"M 19.1875 8.296875 \n",
+       "L 53.609375 8.296875 \n",
+       "L 53.609375 0 \n",
+       "L 7.328125 0 \n",
+       "L 7.328125 8.296875 \n",
+       "Q 12.9375 14.109375 22.625 23.890625 \n",
+       "Q 32.328125 33.6875 34.8125 36.53125 \n",
+       "Q 39.546875 41.84375 41.421875 45.53125 \n",
+       "Q 43.3125 49.21875 43.3125 52.78125 \n",
+       "Q 43.3125 58.59375 39.234375 62.25 \n",
+       "Q 35.15625 65.921875 28.609375 65.921875 \n",
+       "Q 23.96875 65.921875 18.8125 64.3125 \n",
+       "Q 13.671875 62.703125 7.8125 59.421875 \n",
+       "L 7.8125 69.390625 \n",
+       "Q 13.765625 71.78125 18.9375 73 \n",
+       "Q 24.125 74.21875 28.421875 74.21875 \n",
+       "Q 39.75 74.21875 46.484375 68.546875 \n",
+       "Q 53.21875 62.890625 53.21875 53.421875 \n",
+       "Q 53.21875 48.921875 51.53125 44.890625 \n",
+       "Q 49.859375 40.875 45.40625 35.40625 \n",
+       "Q 44.1875 33.984375 37.640625 27.21875 \n",
+       "Q 31.109375 20.453125 19.1875 8.296875 \n",
+       "\" id=\"BitstreamVeraSans-Roman-32\"/>\n",
+       "    </defs>\n",
+       "    <g transform=\"translate(349.77774807 146.915694411)scale(0.12 -0.12)\">\n",
+       "     <use xlink:href=\"#BitstreamVeraSans-Roman-32\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"Line3DCollection_3\">\n",
+       "    <path d=\"M 312.28365 221.606507 \n",
+       "L 151.89576 177.276724 \n",
+       "L 52.878634 256.572102 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 312.968008 205.643528 \n",
+       "L 151.727332 161.751965 \n",
+       "L 52.1486 240.277261 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 313.659745 189.508416 \n",
+       "L 151.557164 146.066818 \n",
+       "L 51.410434 223.80089 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 314.358982 173.19837 \n",
+       "L 151.385229 130.218786 \n",
+       "L 50.663999 207.13994 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 315.065841 156.710531 \n",
+       "L 151.211499 114.205317 \n",
+       "L 49.909154 190.29129 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 315.780448 140.041976 \n",
+       "L 151.035946 98.023808 \n",
+       "L 49.145757 173.251751 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 316.502931 123.189716 \n",
+       "L 150.858541 81.6716 \n",
+       "L 48.373662 156.018061 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 317.23342 106.150698 \n",
+       "L 150.679255 65.145977 \n",
+       "L 47.592719 138.586882 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 317.972049 88.921801 \n",
+       "L 150.498057 48.444166 \n",
+       "L 46.802775 120.9548 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "    <path d=\"M 318.718956 71.499833 \n",
+       "L 150.314917 31.563334 \n",
+       "L 46.003674 103.118321 \n",
+       "\" style=\"fill:none;stroke:#e6e6e6;\"/>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_15\">\n",
+       "    <g id=\"line2d_18\">\n",
+       "     <path d=\"M 310.945442 221.236638 \n",
+       "L 314.962849 222.347014 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_16\">\n",
+       "    <g id=\"line2d_19\">\n",
+       "     <path d=\"M 311.622388 205.277235 \n",
+       "L 315.662062 206.376881 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_17\">\n",
+       "    <g id=\"line2d_20\">\n",
+       "     <path d=\"M 312.30663 189.145797 \n",
+       "L 316.36882 190.234416 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_18\">\n",
+       "    <g id=\"line2d_21\">\n",
+       "     <path d=\"M 312.998289 172.839527 \n",
+       "L 317.083245 173.916816 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_19\">\n",
+       "    <g id=\"line2d_22\">\n",
+       "     <path d=\"M 313.697484 156.355568 \n",
+       "L 317.805465 157.421213 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_20\">\n",
+       "    <g id=\"line2d_23\">\n",
+       "     <path d=\"M 314.40434 139.690999 \n",
+       "L 318.535605 140.74468 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_21\">\n",
+       "    <g id=\"line2d_24\">\n",
+       "     <path d=\"M 315.118984 122.842835 \n",
+       "L 319.273798 123.884223 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_22\">\n",
+       "    <g id=\"line2d_25\">\n",
+       "     <path d=\"M 315.841544 105.808026 \n",
+       "L 320.020178 106.836783 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_23\">\n",
+       "    <g id=\"line2d_26\">\n",
+       "     <path d=\"M 316.572154 88.583453 \n",
+       "L 320.774882 89.599232 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "   <g id=\"xtick_24\">\n",
+       "    <g id=\"line2d_27\">\n",
+       "     <path d=\"M 317.310948 71.165928 \n",
+       "L 321.538049 72.168372 \n",
+       "\" style=\"fill:none;stroke:#000000;stroke-linecap:square;\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "  </g>\n",
+       "  <g id=\"axes_1\">\n",
+       "   <g id=\"Path3DCollection_1\">\n",
+       "    <defs>\n",
+       "     <path d=\"M 0 2.236068 \n",
+       "C 0.593012 2.236068 1.161816 2.000462 1.581139 1.581139 \n",
+       "C 2.000462 1.161816 2.236068 0.593012 2.236068 0 \n",
+       "C 2.236068 -0.593012 2.000462 -1.161816 1.581139 -1.581139 \n",
+       "C 1.161816 -2.000462 0.593012 -2.236068 0 -2.236068 \n",
+       "C -0.593012 -2.236068 -1.161816 -2.000462 -1.581139 -1.581139 \n",
+       "C -2.000462 -1.161816 -2.236068 -0.593012 -2.236068 0 \n",
+       "C -2.236068 0.593012 -2.000462 1.161816 -1.581139 1.581139 \n",
+       "C -1.161816 2.000462 -0.593012 2.236068 0 2.236068 \n",
+       "z\n",
+       "\" id=\"C0_0_3af6fb4475\"/>\n",
+       "    </defs>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.392127278915;stroke:#000000;stroke-opacity:0.392127278915;\" x=\"157.096618502\" xlink:href=\"#C0_0_3af6fb4475\" y=\"134.753024433\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.533054753068;stroke:#000000;stroke-opacity:0.533054753068;\" x=\"188.192468251\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.658825277\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.657495988188;stroke:#000000;stroke-opacity:0.657495988188;\" x=\"209.749147685\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.690469719\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.329118771127;stroke:#000000;stroke-opacity:0.329118771127;\" x=\"154.191900173\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.784214423\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.445479643457;stroke:#000000;stroke-opacity:0.445479643457;\" x=\"147.290529918\" xlink:href=\"#C0_0_3af6fb4475\" y=\"130.216976738\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.323948455537;stroke:#000000;stroke-opacity:0.323948455537;\" x=\"170.863320342\" xlink:href=\"#C0_0_3af6fb4475\" y=\"152.957961088\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.567160517477;stroke:#000000;stroke-opacity:0.567160517477;\" x=\"120.134420811\" xlink:href=\"#C0_0_3af6fb4475\" y=\"192.203148731\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.323877919987;stroke:#000000;stroke-opacity:0.323877919987;\" x=\"167.365121772\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.628005137\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.511750277936;stroke:#000000;stroke-opacity:0.511750277936;\" x=\"154.992139409\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.213797184\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.484999658091;stroke:#000000;stroke-opacity:0.484999658091;\" x=\"122.744382383\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.444534335\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.353746586389;stroke:#000000;stroke-opacity:0.353746586389;\" x=\"168.037032682\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.291223355\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.383626965565;stroke:#000000;stroke-opacity:0.383626965565;\" x=\"151.626447088\" xlink:href=\"#C0_0_3af6fb4475\" y=\"131.504324407\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.430570921661;stroke:#000000;stroke-opacity:0.430570921661;\" x=\"165.082078383\" xlink:href=\"#C0_0_3af6fb4475\" y=\"137.278412067\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.421381526297;stroke:#000000;stroke-opacity:0.421381526297;\" x=\"150.033879445\" xlink:href=\"#C0_0_3af6fb4475\" y=\"133.106497509\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.352774648625;stroke:#000000;stroke-opacity:0.352774648625;\" x=\"160.13383915\" xlink:href=\"#C0_0_3af6fb4475\" y=\"145.042691418\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.425634705279;stroke:#000000;stroke-opacity:0.425634705279;\" x=\"147.137158405\" xlink:href=\"#C0_0_3af6fb4475\" y=\"127.509278111\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.460623506446;stroke:#000000;stroke-opacity:0.460623506446;\" x=\"150.251874559\" xlink:href=\"#C0_0_3af6fb4475\" y=\"123.296846061\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.516804197677;stroke:#000000;stroke-opacity:0.516804197677;\" x=\"175.288738233\" xlink:href=\"#C0_0_3af6fb4475\" y=\"130.797394744\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.514215152543;stroke:#000000;stroke-opacity:0.514215152543;\" x=\"146.783051035\" xlink:href=\"#C0_0_3af6fb4475\" y=\"121.188862518\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.43444245302;stroke:#000000;stroke-opacity:0.43444245302;\" x=\"165.019243913\" xlink:href=\"#C0_0_3af6fb4475\" y=\"135.181598807\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.424286223894;stroke:#000000;stroke-opacity:0.424286223894;\" x=\"154.193994327\" xlink:href=\"#C0_0_3af6fb4475\" y=\"132.483672848\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.33778823146;stroke:#000000;stroke-opacity:0.33778823146;\" x=\"160.323570295\" xlink:href=\"#C0_0_3af6fb4475\" y=\"143.313529365\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.376453136376;stroke:#000000;stroke-opacity:0.376453136376;\" x=\"176.753545435\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.073267842\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.33956908797;stroke:#000000;stroke-opacity:0.33956908797;\" x=\"150.408393293\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.278299255\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.325254503225;stroke:#000000;stroke-opacity:0.325254503225;\" x=\"157.935610067\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.353931553\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.379165888949;stroke:#000000;stroke-opacity:0.379165888949;\" x=\"157.150480933\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.480334687\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.555614382998;stroke:#000000;stroke-opacity:0.555614382998;\" x=\"147.287449332\" xlink:href=\"#C0_0_3af6fb4475\" y=\"121.265379416\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.441059390472;stroke:#000000;stroke-opacity:0.441059390472;\" x=\"154.313775506\" xlink:href=\"#C0_0_3af6fb4475\" y=\"168.461953756\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.447951856954;stroke:#000000;stroke-opacity:0.447951856954;\" x=\"170.889651924\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.262737763\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.885192764734;stroke:#000000;stroke-opacity:0.885192764734;\" x=\"110.728974067\" xlink:href=\"#C0_0_3af6fb4475\" y=\"101.722573462\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.595605630098;stroke:#000000;stroke-opacity:0.595605630098;\" x=\"153.143025213\" xlink:href=\"#C0_0_3af6fb4475\" y=\"117.464615561\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.371507475505;stroke:#000000;stroke-opacity:0.371507475505;\" x=\"157.761350284\" xlink:href=\"#C0_0_3af6fb4475\" y=\"134.675113401\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.39291720237;stroke:#000000;stroke-opacity:0.39291720237;\" x=\"146.682705717\" xlink:href=\"#C0_0_3af6fb4475\" y=\"137.049137826\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.383909028218;stroke:#000000;stroke-opacity:0.383909028218;\" x=\"161.642660461\" xlink:href=\"#C0_0_3af6fb4475\" y=\"132.634445191\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.510289236292;stroke:#000000;stroke-opacity:0.510289236292;\" x=\"155.949369783\" xlink:href=\"#C0_0_3af6fb4475\" y=\"125.04199611\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.500074098103;stroke:#000000;stroke-opacity:0.500074098103;\" x=\"144.570814201\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.869636377\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.387021508256;stroke:#000000;stroke-opacity:0.387021508256;\" x=\"175.215171994\" xlink:href=\"#C0_0_3af6fb4475\" y=\"143.388747092\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.349826415435;stroke:#000000;stroke-opacity:0.349826415435;\" x=\"150.881394524\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.418297885\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.902990004704;stroke:#000000;stroke-opacity:0.902990004704;\" x=\"206.124006356\" xlink:href=\"#C0_0_3af6fb4475\" y=\"184.91820164\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.795552541384;stroke:#000000;stroke-opacity:0.795552541384;\" x=\"117.37187808\" xlink:href=\"#C0_0_3af6fb4475\" y=\"105.04148424\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.450952298233;stroke:#000000;stroke-opacity:0.450952298233;\" x=\"181.02096818\" xlink:href=\"#C0_0_3af6fb4475\" y=\"136.790103902\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.596129231631;stroke:#000000;stroke-opacity:0.596129231631;\" x=\"168.696227825\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.811178026\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.607873217595;stroke:#000000;stroke-opacity:0.607873217595;\" x=\"116.202474147\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.782433287\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.83782296045;stroke:#000000;stroke-opacity:0.83782296045;\" x=\"118.364213316\" xlink:href=\"#C0_0_3af6fb4475\" y=\"111.297004232\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.46459367203;stroke:#000000;stroke-opacity:0.46459367203;\" x=\"146.173988724\" xlink:href=\"#C0_0_3af6fb4475\" y=\"122.920547365\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.58854023332;stroke:#000000;stroke-opacity:0.58854023332;\" x=\"115.326330174\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.382215316\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.353453003565;stroke:#000000;stroke-opacity:0.353453003565;\" x=\"158.300564162\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.435565437\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.856697942793;stroke:#000000;stroke-opacity:0.856697942793;\" x=\"115.485063661\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.895410009\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.503110318314;stroke:#000000;stroke-opacity:0.503110318314;\" x=\"178.221108528\" xlink:href=\"#C0_0_3af6fb4475\" y=\"126.736356346\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.637778346959;stroke:#000000;stroke-opacity:0.637778346959;\" x=\"113.046088264\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.33657788\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.56140404309;stroke:#000000;stroke-opacity:0.56140404309;\" x=\"113.403718796\" xlink:href=\"#C0_0_3af6fb4475\" y=\"182.756326208\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.497438199128;stroke:#000000;stroke-opacity:0.497438199128;\" x=\"162.497928313\" xlink:href=\"#C0_0_3af6fb4475\" y=\"127.828091054\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.401665655098;stroke:#000000;stroke-opacity:0.401665655098;\" x=\"139.25684264\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.963504409\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.401271938555;stroke:#000000;stroke-opacity:0.401271938555;\" x=\"158.427637629\" xlink:href=\"#C0_0_3af6fb4475\" y=\"129.145049707\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.448173617677;stroke:#000000;stroke-opacity:0.448173617677;\" x=\"161.246119773\" xlink:href=\"#C0_0_3af6fb4475\" y=\"128.211832917\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.516984768541;stroke:#000000;stroke-opacity:0.516984768541;\" x=\"177.969798727\" xlink:href=\"#C0_0_3af6fb4475\" y=\"131.123349821\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.441384623022;stroke:#000000;stroke-opacity:0.441384623022;\" x=\"180.998174772\" xlink:href=\"#C0_0_3af6fb4475\" y=\"145.784381742\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.826145686662;stroke:#000000;stroke-opacity:0.826145686662;\" x=\"117.030045911\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.665808142\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.417573202674;stroke:#000000;stroke-opacity:0.417573202674;\" x=\"136.572595053\" xlink:href=\"#C0_0_3af6fb4475\" y=\"178.724683768\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.416000315523;stroke:#000000;stroke-opacity:0.416000315523;\" x=\"162.879807096\" xlink:href=\"#C0_0_3af6fb4475\" y=\"131.023413373\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.49042035515;stroke:#000000;stroke-opacity:0.49042035515;\" x=\"128.736485457\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.946282977\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.380984242271;stroke:#000000;stroke-opacity:0.380984242271;\" x=\"157.53847414\" xlink:href=\"#C0_0_3af6fb4475\" y=\"143.303962804\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.426160677089;stroke:#000000;stroke-opacity:0.426160677089;\" x=\"133.763243161\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.135332125\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.76896645398;stroke:#000000;stroke-opacity:0.76896645398;\" x=\"118.119649545\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.874863474\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.881070030588;stroke:#000000;stroke-opacity:0.881070030588;\" x=\"105.454696273\" xlink:href=\"#C0_0_3af6fb4475\" y=\"107.669621044\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.341153262486;stroke:#000000;stroke-opacity:0.341153262486;\" x=\"152.772915779\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.012575412\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.301412773369;stroke:#000000;stroke-opacity:0.301412773369;\" x=\"163.221013161\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.979266171\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.312872371969;stroke:#000000;stroke-opacity:0.312872371969;\" x=\"165.391871085\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.009864686\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.652212689635;stroke:#000000;stroke-opacity:0.652212689635;\" x=\"198.250661833\" xlink:href=\"#C0_0_3af6fb4475\" y=\"138.088899565\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.772176067613;stroke:#000000;stroke-opacity:0.772176067613;\" x=\"110.174974269\" xlink:href=\"#C0_0_3af6fb4475\" y=\"236.093833073\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.789616002534;stroke:#000000;stroke-opacity:0.789616002534;\" x=\"104.112351135\" xlink:href=\"#C0_0_3af6fb4475\" y=\"242.633465397\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.804672206557;stroke:#000000;stroke-opacity:0.804672206557;\" x=\"104.369311578\" xlink:href=\"#C0_0_3af6fb4475\" y=\"241.916794815\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.786448677078;stroke:#000000;stroke-opacity:0.786448677078;\" x=\"102.338661619\" xlink:href=\"#C0_0_3af6fb4475\" y=\"241.948944936\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.790161473263;stroke:#000000;stroke-opacity:0.790161473263;\" x=\"110.307061861\" xlink:href=\"#C0_0_3af6fb4475\" y=\"240.681783117\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.760981045104;stroke:#000000;stroke-opacity:0.760981045104;\" x=\"105.434068338\" xlink:href=\"#C0_0_3af6fb4475\" y=\"229.071859779\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.768019072714;stroke:#000000;stroke-opacity:0.768019072714;\" x=\"115.643258258\" xlink:href=\"#C0_0_3af6fb4475\" y=\"230.710808381\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.826958443746;stroke:#000000;stroke-opacity:0.826958443746;\" x=\"98.0877666069\" xlink:href=\"#C0_0_3af6fb4475\" y=\"229.407608407\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.812778778775;stroke:#000000;stroke-opacity:0.812778778775;\" x=\"100.239843593\" xlink:href=\"#C0_0_3af6fb4475\" y=\"240.006041391\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.78347415245;stroke:#000000;stroke-opacity:0.78347415245;\" x=\"107.242960261\" xlink:href=\"#C0_0_3af6fb4475\" y=\"229.948031923\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.579350238797;stroke:#000000;stroke-opacity:0.579350238797;\" x=\"118.117643816\" xlink:href=\"#C0_0_3af6fb4475\" y=\"201.538328175\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.527346192529;stroke:#000000;stroke-opacity:0.527346192529;\" x=\"121.356792213\" xlink:href=\"#C0_0_3af6fb4475\" y=\"188.756984707\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.819547983886;stroke:#000000;stroke-opacity:0.819547983886;\" x=\"93.0322062402\" xlink:href=\"#C0_0_3af6fb4475\" y=\"225.008179543\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.769053424064;stroke:#000000;stroke-opacity:0.769053424064;\" x=\"111.757431647\" xlink:href=\"#C0_0_3af6fb4475\" y=\"243.974312783\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.759390511039;stroke:#000000;stroke-opacity:0.759390511039;\" x=\"114.399433835\" xlink:href=\"#C0_0_3af6fb4475\" y=\"232.071473617\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.788722353424;stroke:#000000;stroke-opacity:0.788722353424;\" x=\"98.8040044387\" xlink:href=\"#C0_0_3af6fb4475\" y=\"227.003425833\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.77709718309;stroke:#000000;stroke-opacity:0.77709718309;\" x=\"106.913149102\" xlink:href=\"#C0_0_3af6fb4475\" y=\"228.43651244\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.940563511529;stroke:#000000;stroke-opacity:0.940563511529;\" x=\"112.351274063\" xlink:href=\"#C0_0_3af6fb4475\" y=\"107.085639414\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.786181292292;stroke:#000000;stroke-opacity:0.786181292292;\" x=\"193.883634572\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.445976697\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.914689419234;stroke:#000000;stroke-opacity:0.914689419234;\" x=\"113.394552223\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.193692829\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.568991381431;stroke:#000000;stroke-opacity:0.568991381431;\" x=\"164.83912653\" xlink:href=\"#C0_0_3af6fb4475\" y=\"129.995301367\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.882355185213;stroke:#000000;stroke-opacity:0.882355185213;\" x=\"116.472225262\" xlink:href=\"#C0_0_3af6fb4475\" y=\"101.358644946\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.943864109686;stroke:#000000;stroke-opacity:0.943864109686;\" x=\"113.234622745\" xlink:href=\"#C0_0_3af6fb4475\" y=\"101.128075187\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.543364148472;stroke:#000000;stroke-opacity:0.543364148472;\" x=\"158.459763661\" xlink:href=\"#C0_0_3af6fb4475\" y=\"131.549594466\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.605813966337;stroke:#000000;stroke-opacity:0.605813966337;\" x=\"138.289107165\" xlink:href=\"#C0_0_3af6fb4475\" y=\"125.366032918\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.692863533482;stroke:#000000;stroke-opacity:0.692863533482;\" x=\"217.006968178\" xlink:href=\"#C0_0_3af6fb4475\" y=\"157.676688879\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.408667450495;stroke:#000000;stroke-opacity:0.408667450495;\" x=\"151.635852059\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.461291071\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.312328532191;stroke:#000000;stroke-opacity:0.312328532191;\" x=\"156.956055376\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.730583129\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.342305683306;stroke:#000000;stroke-opacity:0.342305683306;\" x=\"158.631889235\" xlink:href=\"#C0_0_3af6fb4475\" y=\"169.926610504\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.894991750599;stroke:#000000;stroke-opacity:0.894991750599;\" x=\"120.386941605\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.386855579\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.337697673899;stroke:#000000;stroke-opacity:0.337697673899;\" x=\"147.666282051\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.473652897\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.887656361277;stroke:#000000;stroke-opacity:0.887656361277;\" x=\"187.763604742\" xlink:href=\"#C0_0_3af6fb4475\" y=\"154.37006014\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.756733730669;stroke:#000000;stroke-opacity:0.756733730669;\" x=\"148.392990728\" xlink:href=\"#C0_0_3af6fb4475\" y=\"122.709053628\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.565635559487;stroke:#000000;stroke-opacity:0.565635559487;\" x=\"169.640707764\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.969834951\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.544629428413;stroke:#000000;stroke-opacity:0.544629428413;\" x=\"170.449557877\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.868077705\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.50663336027;stroke:#000000;stroke-opacity:0.50663336027;\" x=\"165.509009548\" xlink:href=\"#C0_0_3af6fb4475\" y=\"125.934321063\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.423217862201;stroke:#000000;stroke-opacity:0.423217862201;\" x=\"177.058241461\" xlink:href=\"#C0_0_3af6fb4475\" y=\"154.985610185\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.387435028976;stroke:#000000;stroke-opacity:0.387435028976;\" x=\"162.305446448\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.323832653\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.467358651902;stroke:#000000;stroke-opacity:0.467358651902;\" x=\"194.603158482\" xlink:href=\"#C0_0_3af6fb4475\" y=\"154.450379102\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.328386270158;stroke:#000000;stroke-opacity:0.328386270158;\" x=\"157.173753904\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.269951928\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.941516334955;stroke:#000000;stroke-opacity:0.941516334955;\" x=\"100.697674714\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.229065155\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.88856511885;stroke:#000000;stroke-opacity:0.88856511885;\" x=\"111.743947329\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.762754058\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.486871609251;stroke:#000000;stroke-opacity:0.486871609251;\" x=\"181.95982358\" xlink:href=\"#C0_0_3af6fb4475\" y=\"133.620635779\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.383950258032;stroke:#000000;stroke-opacity:0.383950258032;\" x=\"158.943162949\" xlink:href=\"#C0_0_3af6fb4475\" y=\"134.743543124\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.834906240029;stroke:#000000;stroke-opacity:0.834906240029;\" x=\"110.991244364\" xlink:href=\"#C0_0_3af6fb4475\" y=\"111.888584355\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.359819895434;stroke:#000000;stroke-opacity:0.359819895434;\" x=\"154.715656089\" xlink:href=\"#C0_0_3af6fb4475\" y=\"138.084004852\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.345533222475;stroke:#000000;stroke-opacity:0.345533222475;\" x=\"162.4987531\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.730368818\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.772935980603;stroke:#000000;stroke-opacity:0.772935980603;\" x=\"215.652405939\" xlink:href=\"#C0_0_3af6fb4475\" y=\"148.51296878\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.319792224795;stroke:#000000;stroke-opacity:0.319792224795;\" x=\"170.519430411\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.481647795\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.943538993977;stroke:#000000;stroke-opacity:0.943538993977;\" x=\"111.542140657\" xlink:href=\"#C0_0_3af6fb4475\" y=\"99.1490887779\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.885904844489;stroke:#000000;stroke-opacity:0.885904844489;\" x=\"129.399605126\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.497851472\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.322432065747;stroke:#000000;stroke-opacity:0.322432065747;\" x=\"171.408813051\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.205093602\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.73388758889;stroke:#000000;stroke-opacity:0.73388758889;\" x=\"244.090969987\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.527343241\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.370570654878;stroke:#000000;stroke-opacity:0.370570654878;\" x=\"176.262150552\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.498009054\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.630990957336;stroke:#000000;stroke-opacity:0.630990957336;\" x=\"196.469276654\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.11062097\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.375052169262;stroke:#000000;stroke-opacity:0.375052169262;\" x=\"170.626691664\" xlink:href=\"#C0_0_3af6fb4475\" y=\"150.260972828\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.400879123752;stroke:#000000;stroke-opacity:0.400879123752;\" x=\"163.323466196\" xlink:href=\"#C0_0_3af6fb4475\" y=\"127.260809817\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.619372943117;stroke:#000000;stroke-opacity:0.619372943117;\" x=\"172.534506198\" xlink:href=\"#C0_0_3af6fb4475\" y=\"124.77893781\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.394003363791;stroke:#000000;stroke-opacity:0.394003363791;\" x=\"169.579497658\" xlink:href=\"#C0_0_3af6fb4475\" y=\"132.482330355\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.514787003428;stroke:#000000;stroke-opacity:0.514787003428;\" x=\"178.962121812\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.346873171\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.926360700951;stroke:#000000;stroke-opacity:0.926360700951;\" x=\"108.156696405\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.702522623\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.503910318244;stroke:#000000;stroke-opacity:0.503910318244;\" x=\"206.542238769\" xlink:href=\"#C0_0_3af6fb4475\" y=\"145.625005143\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.863868196153;stroke:#000000;stroke-opacity:0.863868196153;\" x=\"123.927608151\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.080761373\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.542048800773;stroke:#000000;stroke-opacity:0.542048800773;\" x=\"211.840032605\" xlink:href=\"#C0_0_3af6fb4475\" y=\"157.429039003\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.360431733317;stroke:#000000;stroke-opacity:0.360431733317;\" x=\"174.674717762\" xlink:href=\"#C0_0_3af6fb4475\" y=\"137.678560273\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.452440633339;stroke:#000000;stroke-opacity:0.452440633339;\" x=\"163.471844301\" xlink:href=\"#C0_0_3af6fb4475\" y=\"124.805545367\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.726619923378;stroke:#000000;stroke-opacity:0.726619923378;\" x=\"141.734916681\" xlink:href=\"#C0_0_3af6fb4475\" y=\"117.037125026\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.939075826464;stroke:#000000;stroke-opacity:0.939075826464;\" x=\"117.599175735\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.396685808\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.470222794418;stroke:#000000;stroke-opacity:0.470222794418;\" x=\"156.323367125\" xlink:href=\"#C0_0_3af6fb4475\" y=\"127.2916625\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.96403443533;stroke:#000000;stroke-opacity:0.96403443533;\" x=\"116.209081218\" xlink:href=\"#C0_0_3af6fb4475\" y=\"101.503589944\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.716263120567;stroke:#000000;stroke-opacity:0.716263120567;\" x=\"204.479437784\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.065128111\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.663204108184;stroke:#000000;stroke-opacity:0.663204108184;\" x=\"194.374911066\" xlink:href=\"#C0_0_3af6fb4475\" y=\"152.824710913\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.345171917819;stroke:#000000;stroke-opacity:0.345171917819;\" x=\"162.449874929\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.592172429\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.526969451859;stroke:#000000;stroke-opacity:0.526969451859;\" x=\"130.21520811\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.656486133\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.534258947191;stroke:#000000;stroke-opacity:0.534258947191;\" x=\"128.990311742\" xlink:href=\"#C0_0_3af6fb4475\" y=\"183.301446424\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.712001883568;stroke:#000000;stroke-opacity:0.712001883568;\" x=\"159.37618086\" xlink:href=\"#C0_0_3af6fb4475\" y=\"173.406488182\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.444055866211;stroke:#000000;stroke-opacity:0.444055866211;\" x=\"158.010900733\" xlink:href=\"#C0_0_3af6fb4475\" y=\"125.945968951\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.432107077078;stroke:#000000;stroke-opacity:0.432107077078;\" x=\"180.303778841\" xlink:href=\"#C0_0_3af6fb4475\" y=\"136.28568939\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.621484852369;stroke:#000000;stroke-opacity:0.621484852369;\" x=\"141.821502636\" xlink:href=\"#C0_0_3af6fb4475\" y=\"173.985906311\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.354791796324;stroke:#000000;stroke-opacity:0.354791796324;\" x=\"143.884641235\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.463402931\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.575471627902;stroke:#000000;stroke-opacity:0.575471627902;\" x=\"130.973032446\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.110323842\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.553620413974;stroke:#000000;stroke-opacity:0.553620413974;\" x=\"168.233499121\" xlink:href=\"#C0_0_3af6fb4475\" y=\"169.193549289\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.60792921608;stroke:#000000;stroke-opacity:0.60792921608;\" x=\"173.217601528\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.411691868\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.625008423686;stroke:#000000;stroke-opacity:0.625008423686;\" x=\"169.633201833\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.248132215\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.721172548203;stroke:#000000;stroke-opacity:0.721172548203;\" x=\"203.265257839\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.280657974\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.767937208684;stroke:#000000;stroke-opacity:0.767937208684;\" x=\"210.805592338\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.448459136\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.872299061479;stroke:#000000;stroke-opacity:0.872299061479;\" x=\"107.514385105\" xlink:href=\"#C0_0_3af6fb4475\" y=\"106.818097225\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.396828085946;stroke:#000000;stroke-opacity:0.396828085946;\" x=\"142.085443686\" xlink:href=\"#C0_0_3af6fb4475\" y=\"168.196525062\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.34444545449;stroke:#000000;stroke-opacity:0.34444545449;\" x=\"170.41222339\" xlink:href=\"#C0_0_3af6fb4475\" y=\"143.256098286\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.360802559109;stroke:#000000;stroke-opacity:0.360802559109;\" x=\"160.39300157\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.283870493\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.471592757131;stroke:#000000;stroke-opacity:0.471592757131;\" x=\"131.287360949\" xlink:href=\"#C0_0_3af6fb4475\" y=\"190.469944537\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.590381653591;stroke:#000000;stroke-opacity:0.590381653591;\" x=\"142.643505338\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.917777435\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.397318606615;stroke:#000000;stroke-opacity:0.397318606615;\" x=\"164.85121593\" xlink:href=\"#C0_0_3af6fb4475\" y=\"171.370567769\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.575825424325;stroke:#000000;stroke-opacity:0.575825424325;\" x=\"193.148074462\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.052226125\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.348498000481;stroke:#000000;stroke-opacity:0.348498000481;\" x=\"158.687022566\" xlink:href=\"#C0_0_3af6fb4475\" y=\"137.526808076\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.343143554717;stroke:#000000;stroke-opacity:0.343143554717;\" x=\"164.317364672\" xlink:href=\"#C0_0_3af6fb4475\" y=\"138.835607748\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.622079448561;stroke:#000000;stroke-opacity:0.622079448561;\" x=\"113.401340887\" xlink:href=\"#C0_0_3af6fb4475\" y=\"183.401870225\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.634813949177;stroke:#000000;stroke-opacity:0.634813949177;\" x=\"189.112138499\" xlink:href=\"#C0_0_3af6fb4475\" y=\"136.256710475\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.370967787216;stroke:#000000;stroke-opacity:0.370967787216;\" x=\"141.548561688\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.678646759\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.360309892059;stroke:#000000;stroke-opacity:0.360309892059;\" x=\"154.827994488\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.606234341\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.39387843049;stroke:#000000;stroke-opacity:0.39387843049;\" x=\"183.030996449\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.503441983\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.329289235809;stroke:#000000;stroke-opacity:0.329289235809;\" x=\"156.622718718\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.94308907\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.309399366348;stroke:#000000;stroke-opacity:0.309399366348;\" x=\"156.244481766\" xlink:href=\"#C0_0_3af6fb4475\" y=\"154.9697594\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.5423582212;stroke:#000000;stroke-opacity:0.5423582212;\" x=\"205.352811223\" xlink:href=\"#C0_0_3af6fb4475\" y=\"165.586955446\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.327944845365;stroke:#000000;stroke-opacity:0.327944845365;\" x=\"161.101653673\" xlink:href=\"#C0_0_3af6fb4475\" y=\"165.57948464\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.345796676421;stroke:#000000;stroke-opacity:0.345796676421;\" x=\"160.76270233\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.742626282\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.363574580644;stroke:#000000;stroke-opacity:0.363574580644;\" x=\"151.712638421\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.302486468\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.3;stroke:#000000;stroke-opacity:0.3;\" x=\"172.170802364\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.287761198\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.385967334091;stroke:#000000;stroke-opacity:0.385967334091;\" x=\"154.313993728\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.358130002\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.456061233307;stroke:#000000;stroke-opacity:0.456061233307;\" x=\"194.998333544\" xlink:href=\"#C0_0_3af6fb4475\" y=\"152.494695244\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.591458176315;stroke:#000000;stroke-opacity:0.591458176315;\" x=\"214.288417388\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.911934935\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.646230909963;stroke:#000000;stroke-opacity:0.646230909963;\" x=\"214.729094159\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.176226534\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.402766405662;stroke:#000000;stroke-opacity:0.402766405662;\" x=\"188.473907829\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.501412451\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.41845630313;stroke:#000000;stroke-opacity:0.41845630313;\" x=\"151.832650487\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.988852979\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.306649356262;stroke:#000000;stroke-opacity:0.306649356262;\" x=\"165.428161941\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.606357557\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.359388652876;stroke:#000000;stroke-opacity:0.359388652876;\" x=\"195.068094064\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.029929648\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.554465623922;stroke:#000000;stroke-opacity:0.554465623922;\" x=\"219.095002914\" xlink:href=\"#C0_0_3af6fb4475\" y=\"154.075977105\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.3417020685;stroke:#000000;stroke-opacity:0.3417020685;\" x=\"181.669103646\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.847751797\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.627759714614;stroke:#000000;stroke-opacity:0.627759714614;\" x=\"178.725742036\" xlink:href=\"#C0_0_3af6fb4475\" y=\"128.457845405\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.368285371483;stroke:#000000;stroke-opacity:0.368285371483;\" x=\"154.558915187\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.468698095\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.57514973968;stroke:#000000;stroke-opacity:0.57514973968;\" x=\"204.826973754\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.637081148\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.781905236922;stroke:#000000;stroke-opacity:0.781905236922;\" x=\"217.340577263\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.470756372\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.31871675876;stroke:#000000;stroke-opacity:0.31871675876;\" x=\"174.068132043\" xlink:href=\"#C0_0_3af6fb4475\" y=\"152.339176799\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.522502855677;stroke:#000000;stroke-opacity:0.522502855677;\" x=\"186.66715266\" xlink:href=\"#C0_0_3af6fb4475\" y=\"129.125226825\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.483855667566;stroke:#000000;stroke-opacity:0.483855667566;\" x=\"207.379898456\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.403662441\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.583677917023;stroke:#000000;stroke-opacity:0.583677917023;\" x=\"168.290505379\" xlink:href=\"#C0_0_3af6fb4475\" y=\"123.834344049\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.788179342219;stroke:#000000;stroke-opacity:0.788179342219;\" x=\"241.915923353\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.285816658\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.591332358894;stroke:#000000;stroke-opacity:0.591332358894;\" x=\"227.727825385\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.052645824\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.582293470851;stroke:#000000;stroke-opacity:0.582293470851;\" x=\"175.884568217\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.105231556\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.599754655817;stroke:#000000;stroke-opacity:0.599754655817;\" x=\"214.397606549\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.490262951\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.395112946816;stroke:#000000;stroke-opacity:0.395112946816;\" x=\"141.594583166\" xlink:href=\"#C0_0_3af6fb4475\" y=\"180.713332235\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.680068324644;stroke:#000000;stroke-opacity:0.680068324644;\" x=\"221.780737839\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.63689151\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.522064385267;stroke:#000000;stroke-opacity:0.522064385267;\" x=\"186.017535487\" xlink:href=\"#C0_0_3af6fb4475\" y=\"133.154500814\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.681531900381;stroke:#000000;stroke-opacity:0.681531900381;\" x=\"175.440081089\" xlink:href=\"#C0_0_3af6fb4475\" y=\"123.480882766\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.968710086299;stroke:#000000;stroke-opacity:0.968710086299;\" x=\"233.452254196\" xlink:href=\"#C0_0_3af6fb4475\" y=\"183.601062813\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.461095431608;stroke:#000000;stroke-opacity:0.461095431608;\" x=\"183.231380329\" xlink:href=\"#C0_0_3af6fb4475\" y=\"148.038413946\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.394895261623;stroke:#000000;stroke-opacity:0.394895261623;\" x=\"159.282581194\" xlink:href=\"#C0_0_3af6fb4475\" y=\"145.248475592\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.44350103451;stroke:#000000;stroke-opacity:0.44350103451;\" x=\"191.666884945\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.929743281\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.4218970991;stroke:#000000;stroke-opacity:0.4218970991;\" x=\"176.064322475\" xlink:href=\"#C0_0_3af6fb4475\" y=\"134.356830194\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.619499337259;stroke:#000000;stroke-opacity:0.619499337259;\" x=\"210.550405641\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.932282947\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.850865416401;stroke:#000000;stroke-opacity:0.850865416401;\" x=\"217.610469284\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.901842979\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.403099271175;stroke:#000000;stroke-opacity:0.403099271175;\" x=\"159.69815036\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.550556086\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.613616119772;stroke:#000000;stroke-opacity:0.613616119772;\" x=\"198.13510817\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.061732421\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.965731002897;stroke:#000000;stroke-opacity:0.965731002897;\" x=\"235.799830316\" xlink:href=\"#C0_0_3af6fb4475\" y=\"190.915911868\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.741712017514;stroke:#000000;stroke-opacity:0.741712017514;\" x=\"232.507051845\" xlink:href=\"#C0_0_3af6fb4475\" y=\"160.524824664\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.53232727393;stroke:#000000;stroke-opacity:0.53232727393;\" x=\"209.17979569\" xlink:href=\"#C0_0_3af6fb4475\" y=\"160.031179487\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.366855536627;stroke:#000000;stroke-opacity:0.366855536627;\" x=\"170.717202648\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.782755423\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.535580854849;stroke:#000000;stroke-opacity:0.535580854849;\" x=\"180.114636935\" xlink:href=\"#C0_0_3af6fb4475\" y=\"165.441491016\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.390969140802;stroke:#000000;stroke-opacity:0.390969140802;\" x=\"187.301690484\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.624023958\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.583188840774;stroke:#000000;stroke-opacity:0.583188840774;\" x=\"174.122567581\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.146828749\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.510226962724;stroke:#000000;stroke-opacity:0.510226962724;\" x=\"189.413951845\" xlink:href=\"#C0_0_3af6fb4475\" y=\"148.891222331\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.321185471533;stroke:#000000;stroke-opacity:0.321185471533;\" x=\"159.48451227\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.09891866\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.491271985274;stroke:#000000;stroke-opacity:0.491271985274;\" x=\"167.377753463\" xlink:href=\"#C0_0_3af6fb4475\" y=\"168.474166256\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.452792899282;stroke:#000000;stroke-opacity:0.452792899282;\" x=\"170.474593975\" xlink:href=\"#C0_0_3af6fb4475\" y=\"133.449299827\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.542261159276;stroke:#000000;stroke-opacity:0.542261159276;\" x=\"147.33026795\" xlink:href=\"#C0_0_3af6fb4475\" y=\"186.14177079\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.389175581103;stroke:#000000;stroke-opacity:0.389175581103;\" x=\"155.92274017\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.794869998\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.588125323696;stroke:#000000;stroke-opacity:0.588125323696;\" x=\"148.395589072\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.918540764\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.574710261376;stroke:#000000;stroke-opacity:0.574710261376;\" x=\"206.313970877\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.238786494\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.308033286045;stroke:#000000;stroke-opacity:0.308033286045;\" x=\"168.96955285\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.597673853\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.52085615977;stroke:#000000;stroke-opacity:0.52085615977;\" x=\"147.255736408\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.556344116\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.453407976109;stroke:#000000;stroke-opacity:0.453407976109;\" x=\"170.296783722\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.467348696\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.938387520488;stroke:#000000;stroke-opacity:0.938387520488;\" x=\"114.557147976\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.86075519\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.675597843173;stroke:#000000;stroke-opacity:0.675597843173;\" x=\"117.495350424\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.840450175\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.762018739125;stroke:#000000;stroke-opacity:0.762018739125;\" x=\"104.384977889\" xlink:href=\"#C0_0_3af6fb4475\" y=\"230.319966927\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.819631270142;stroke:#000000;stroke-opacity:0.819631270142;\" x=\"106.783831588\" xlink:href=\"#C0_0_3af6fb4475\" y=\"230.919311648\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.809642494731;stroke:#000000;stroke-opacity:0.809642494731;\" x=\"112.674626618\" xlink:href=\"#C0_0_3af6fb4475\" y=\"232.835245664\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.788919892288;stroke:#000000;stroke-opacity:0.788919892288;\" x=\"92.8953376406\" xlink:href=\"#C0_0_3af6fb4475\" y=\"233.465314935\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.809006967914;stroke:#000000;stroke-opacity:0.809006967914;\" x=\"105.562373511\" xlink:href=\"#C0_0_3af6fb4475\" y=\"221.743299958\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.791145270437;stroke:#000000;stroke-opacity:0.791145270437;\" x=\"105.945257329\" xlink:href=\"#C0_0_3af6fb4475\" y=\"239.630862786\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.495622409821;stroke:#000000;stroke-opacity:0.495622409821;\" x=\"180.856604832\" xlink:href=\"#C0_0_3af6fb4475\" y=\"140.022411721\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.801708121021;stroke:#000000;stroke-opacity:0.801708121021;\" x=\"201.745326744\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.952997363\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.883510728889;stroke:#000000;stroke-opacity:0.883510728889;\" x=\"199.038236859\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.765966538\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.376495604631;stroke:#000000;stroke-opacity:0.376495604631;\" x=\"160.028801995\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.672946176\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.365411991985;stroke:#000000;stroke-opacity:0.365411991985;\" x=\"158.644567207\" xlink:href=\"#C0_0_3af6fb4475\" y=\"161.645699295\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.367276148288;stroke:#000000;stroke-opacity:0.367276148288;\" x=\"165.114473853\" xlink:href=\"#C0_0_3af6fb4475\" y=\"165.476381013\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.416469240264;stroke:#000000;stroke-opacity:0.416469240264;\" x=\"194.794080164\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.950477946\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.401295087116;stroke:#000000;stroke-opacity:0.401295087116;\" x=\"180.333095613\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.585872921\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.364636992542;stroke:#000000;stroke-opacity:0.364636992542;\" x=\"167.196147849\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.74327489\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.887182699507;stroke:#000000;stroke-opacity:0.887182699507;\" x=\"223.425710563\" xlink:href=\"#C0_0_3af6fb4475\" y=\"175.994582063\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.341893977579;stroke:#000000;stroke-opacity:0.341893977579;\" x=\"169.363453561\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.470806248\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.31144034065;stroke:#000000;stroke-opacity:0.31144034065;\" x=\"167.970575496\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.305319247\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.522701167737;stroke:#000000;stroke-opacity:0.522701167737;\" x=\"152.081046198\" xlink:href=\"#C0_0_3af6fb4475\" y=\"120.53858841\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.781974410719;stroke:#000000;stroke-opacity:0.781974410719;\" x=\"214.148194551\" xlink:href=\"#C0_0_3af6fb4475\" y=\"145.760954091\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.343932633867;stroke:#000000;stroke-opacity:0.343932633867;\" x=\"170.807843148\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.754239754\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.796091980294;stroke:#000000;stroke-opacity:0.796091980294;\" x=\"188.011985303\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.327096653\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.924375336271;stroke:#000000;stroke-opacity:0.924375336271;\" x=\"119.844416652\" xlink:href=\"#C0_0_3af6fb4475\" y=\"105.878001984\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.341714972251;stroke:#000000;stroke-opacity:0.341714972251;\" x=\"168.033549961\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.654239286\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.779420308738;stroke:#000000;stroke-opacity:0.779420308738;\" x=\"105.554906321\" xlink:href=\"#C0_0_3af6fb4475\" y=\"227.341266916\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.346757270883;stroke:#000000;stroke-opacity:0.346757270883;\" x=\"154.746731266\" xlink:href=\"#C0_0_3af6fb4475\" y=\"150.06145266\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.805646220295;stroke:#000000;stroke-opacity:0.805646220295;\" x=\"107.079579727\" xlink:href=\"#C0_0_3af6fb4475\" y=\"238.935215942\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.797761378145;stroke:#000000;stroke-opacity:0.797761378145;\" x=\"103.112356763\" xlink:href=\"#C0_0_3af6fb4475\" y=\"240.474476137\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.818010947291;stroke:#000000;stroke-opacity:0.818010947291;\" x=\"108.770809499\" xlink:href=\"#C0_0_3af6fb4475\" y=\"230.07659111\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.81356051272;stroke:#000000;stroke-opacity:0.81356051272;\" x=\"102.030272845\" xlink:href=\"#C0_0_3af6fb4475\" y=\"235.749403737\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.799129751379;stroke:#000000;stroke-opacity:0.799129751379;\" x=\"108.941027731\" xlink:href=\"#C0_0_3af6fb4475\" y=\"247.460829546\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.77959095119;stroke:#000000;stroke-opacity:0.77959095119;\" x=\"108.210579097\" xlink:href=\"#C0_0_3af6fb4475\" y=\"238.016284062\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.825073309604;stroke:#000000;stroke-opacity:0.825073309604;\" x=\"112.271247767\" xlink:href=\"#C0_0_3af6fb4475\" y=\"237.795384281\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.79638452993;stroke:#000000;stroke-opacity:0.79638452993;\" x=\"104.939569767\" xlink:href=\"#C0_0_3af6fb4475\" y=\"234.31583506\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.747796605333;stroke:#000000;stroke-opacity:0.747796605333;\" x=\"113.900313261\" xlink:href=\"#C0_0_3af6fb4475\" y=\"233.912141677\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.807289989408;stroke:#000000;stroke-opacity:0.807289989408;\" x=\"119.802276351\" xlink:href=\"#C0_0_3af6fb4475\" y=\"222.13347159\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.627917358985;stroke:#000000;stroke-opacity:0.627917358985;\" x=\"226.833885397\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.376148562\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.552900211716;stroke:#000000;stroke-opacity:0.552900211716;\" x=\"211.972500827\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.941866753\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.804618348659;stroke:#000000;stroke-opacity:0.804618348659;\" x=\"125.857685735\" xlink:href=\"#C0_0_3af6fb4475\" y=\"205.145460004\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.820312786316;stroke:#000000;stroke-opacity:0.820312786316;\" x=\"169.488943052\" xlink:href=\"#C0_0_3af6fb4475\" y=\"180.894491033\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.890422518379;stroke:#000000;stroke-opacity:0.890422518379;\" x=\"241.995066607\" xlink:href=\"#C0_0_3af6fb4475\" y=\"181.048440532\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.464130220928;stroke:#000000;stroke-opacity:0.464130220928;\" x=\"168.12492074\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.852653235\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.866558811197;stroke:#000000;stroke-opacity:0.866558811197;\" x=\"160.448224021\" xlink:href=\"#C0_0_3af6fb4475\" y=\"183.63814469\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.885400590813;stroke:#000000;stroke-opacity:0.885400590813;\" x=\"201.127994773\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.712340628\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.69789135446;stroke:#000000;stroke-opacity:0.69789135446;\" x=\"147.688710443\" xlink:href=\"#C0_0_3af6fb4475\" y=\"112.602677448\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.692481087079;stroke:#000000;stroke-opacity:0.692481087079;\" x=\"192.449177298\" xlink:href=\"#C0_0_3af6fb4475\" y=\"148.771662901\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.60327454205;stroke:#000000;stroke-opacity:0.60327454205;\" x=\"223.427384142\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.474922265\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.404515926251;stroke:#000000;stroke-opacity:0.404515926251;\" x=\"158.911849769\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.92699605\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.910220623904;stroke:#000000;stroke-opacity:0.910220623904;\" x=\"118.654373475\" xlink:href=\"#C0_0_3af6fb4475\" y=\"98.2179791391\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.379861043582;stroke:#000000;stroke-opacity:0.379861043582;\" x=\"190.725003939\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.45575848\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.551926228318;stroke:#000000;stroke-opacity:0.551926228318;\" x=\"158.294189973\" xlink:href=\"#C0_0_3af6fb4475\" y=\"181.803344044\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.661864227865;stroke:#000000;stroke-opacity:0.661864227865;\" x=\"209.323913602\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.523143266\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.337308015776;stroke:#000000;stroke-opacity:0.337308015776;\" x=\"176.001715831\" xlink:href=\"#C0_0_3af6fb4475\" y=\"157.920582439\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.775863403105;stroke:#000000;stroke-opacity:0.775863403105;\" x=\"105.086928203\" xlink:href=\"#C0_0_3af6fb4475\" y=\"242.616261778\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.614476481328;stroke:#000000;stroke-opacity:0.614476481328;\" x=\"180.592305569\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.49952955\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.495349317324;stroke:#000000;stroke-opacity:0.495349317324;\" x=\"203.462153279\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.326219973\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.349885521165;stroke:#000000;stroke-opacity:0.349885521165;\" x=\"160.219511418\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.635373288\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.763678085925;stroke:#000000;stroke-opacity:0.763678085925;\" x=\"178.633114357\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.351861245\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.619006842581;stroke:#000000;stroke-opacity:0.619006842581;\" x=\"213.042887956\" xlink:href=\"#C0_0_3af6fb4475\" y=\"153.844503774\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.45974162992;stroke:#000000;stroke-opacity:0.45974162992;\" x=\"179.905830854\" xlink:href=\"#C0_0_3af6fb4475\" y=\"137.935579561\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.774192644479;stroke:#000000;stroke-opacity:0.774192644479;\" x=\"174.888532037\" xlink:href=\"#C0_0_3af6fb4475\" y=\"134.625448482\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.414311226498;stroke:#000000;stroke-opacity:0.414311226498;\" x=\"181.476845447\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.016157776\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.685223549145;stroke:#000000;stroke-opacity:0.685223549145;\" x=\"203.639204472\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.737717644\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.634731085009;stroke:#000000;stroke-opacity:0.634731085009;\" x=\"226.276892707\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.101295747\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.38986748539;stroke:#000000;stroke-opacity:0.38986748539;\" x=\"192.448493709\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.497998231\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.774085888368;stroke:#000000;stroke-opacity:0.774085888368;\" x=\"109.421430644\" xlink:href=\"#C0_0_3af6fb4475\" y=\"235.195843406\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.461657566523;stroke:#000000;stroke-opacity:0.461657566523;\" x=\"175.41322567\" xlink:href=\"#C0_0_3af6fb4475\" y=\"129.802049319\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.930988711968;stroke:#000000;stroke-opacity:0.930988711968;\" x=\"109.083147469\" xlink:href=\"#C0_0_3af6fb4475\" y=\"106.68038316\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.595337505006;stroke:#000000;stroke-opacity:0.595337505006;\" x=\"159.806946239\" xlink:href=\"#C0_0_3af6fb4475\" y=\"129.688126693\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.984242722231;stroke:#000000;stroke-opacity:0.984242722231;\" x=\"110.615059607\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.046834081\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.966332290434;stroke:#000000;stroke-opacity:0.966332290434;\" x=\"107.990453944\" xlink:href=\"#C0_0_3af6fb4475\" y=\"103.171085387\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.93230427374;stroke:#000000;stroke-opacity:0.93230427374;\" x=\"108.950851616\" xlink:href=\"#C0_0_3af6fb4475\" y=\"106.443135758\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.930596366763;stroke:#000000;stroke-opacity:0.930596366763;\" x=\"110.596038256\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.530304905\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.964160357298;stroke:#000000;stroke-opacity:0.964160357298;\" x=\"105.512812103\" xlink:href=\"#C0_0_3af6fb4475\" y=\"102.936189709\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.949259991976;stroke:#000000;stroke-opacity:0.949259991976;\" x=\"107.74308953\" xlink:href=\"#C0_0_3af6fb4475\" y=\"103.961983955\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.919195288063;stroke:#000000;stroke-opacity:0.919195288063;\" x=\"110.416366922\" xlink:href=\"#C0_0_3af6fb4475\" y=\"103.262437171\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.879597527766;stroke:#000000;stroke-opacity:0.879597527766;\" x=\"119.917659505\" xlink:href=\"#C0_0_3af6fb4475\" y=\"100.801448756\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.988137895465;stroke:#000000;stroke-opacity:0.988137895465;\" x=\"113.973909881\" xlink:href=\"#C0_0_3af6fb4475\" y=\"110.190875086\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.901188981263;stroke:#000000;stroke-opacity:0.901188981263;\" x=\"120.355068097\" xlink:href=\"#C0_0_3af6fb4475\" y=\"100.83880029\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.731193367139;stroke:#000000;stroke-opacity:0.731193367139;\" x=\"232.778572332\" xlink:href=\"#C0_0_3af6fb4475\" y=\"175.154986042\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.622475779359;stroke:#000000;stroke-opacity:0.622475779359;\" x=\"219.038700482\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.568019277\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.80369116037;stroke:#000000;stroke-opacity:0.80369116037;\" x=\"201.767169089\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.35875441\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.805286157061;stroke:#000000;stroke-opacity:0.805286157061;\" x=\"103.919014178\" xlink:href=\"#C0_0_3af6fb4475\" y=\"246.702034302\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.552293473364;stroke:#000000;stroke-opacity:0.552293473364;\" x=\"178.620115421\" xlink:href=\"#C0_0_3af6fb4475\" y=\"157.271754726\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.464449983831;stroke:#000000;stroke-opacity:0.464449983831;\" x=\"193.900471659\" xlink:href=\"#C0_0_3af6fb4475\" y=\"156.376442407\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.467129123907;stroke:#000000;stroke-opacity:0.467129123907;\" x=\"213.055642751\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.88013971\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.917491242946;stroke:#000000;stroke-opacity:0.917491242946;\" x=\"226.557151717\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.272665692\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.487891571178;stroke:#000000;stroke-opacity:0.487891571178;\" x=\"180.457663238\" xlink:href=\"#C0_0_3af6fb4475\" y=\"136.081183528\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.589666408278;stroke:#000000;stroke-opacity:0.589666408278;\" x=\"188.429381027\" xlink:href=\"#C0_0_3af6fb4475\" y=\"130.860172921\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.958185069944;stroke:#000000;stroke-opacity:0.958185069944;\" x=\"121.061388271\" xlink:href=\"#C0_0_3af6fb4475\" y=\"109.328231128\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.703906663578;stroke:#000000;stroke-opacity:0.703906663578;\" x=\"213.838478191\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.395266172\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.946142686395;stroke:#000000;stroke-opacity:0.946142686395;\" x=\"108.311019272\" xlink:href=\"#C0_0_3af6fb4475\" y=\"100.843032115\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.569647873261;stroke:#000000;stroke-opacity:0.569647873261;\" x=\"227.737729551\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.007131132\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.612686984173;stroke:#000000;stroke-opacity:0.612686984173;\" x=\"215.186433941\" xlink:href=\"#C0_0_3af6fb4475\" y=\"152.464394637\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.668359175335;stroke:#000000;stroke-opacity:0.668359175335;\" x=\"202.027697833\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.537754627\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.804282354571;stroke:#000000;stroke-opacity:0.804282354571;\" x=\"238.7711934\" xlink:href=\"#C0_0_3af6fb4475\" y=\"174.621583545\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.675972860164;stroke:#000000;stroke-opacity:0.675972860164;\" x=\"228.920412054\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.299363262\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.794442202765;stroke:#000000;stroke-opacity:0.794442202765;\" x=\"234.655117782\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.88675862\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.48474984343;stroke:#000000;stroke-opacity:0.48474984343;\" x=\"187.336790459\" xlink:href=\"#C0_0_3af6fb4475\" y=\"138.696225843\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.670317255917;stroke:#000000;stroke-opacity:0.670317255917;\" x=\"216.485276974\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.741242614\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.696265131677;stroke:#000000;stroke-opacity:0.696265131677;\" x=\"227.063490838\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.055868558\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.696618358912;stroke:#000000;stroke-opacity:0.696618358912;\" x=\"214.382804477\" xlink:href=\"#C0_0_3af6fb4475\" y=\"157.802433176\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.888292451181;stroke:#000000;stroke-opacity:0.888292451181;\" x=\"239.681267353\" xlink:href=\"#C0_0_3af6fb4475\" y=\"177.656788971\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.579647867949;stroke:#000000;stroke-opacity:0.579647867949;\" x=\"200.178051513\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.374173956\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.701301751547;stroke:#000000;stroke-opacity:0.701301751547;\" x=\"210.629230403\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.638645386\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.506601931701;stroke:#000000;stroke-opacity:0.506601931701;\" x=\"220.178393954\" xlink:href=\"#C0_0_3af6fb4475\" y=\"159.706043417\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.671642121824;stroke:#000000;stroke-opacity:0.671642121824;\" x=\"181.479295965\" xlink:href=\"#C0_0_3af6fb4475\" y=\"130.838972235\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.642652964519;stroke:#000000;stroke-opacity:0.642652964519;\" x=\"206.758887586\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.792060264\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.63582977751;stroke:#000000;stroke-opacity:0.63582977751;\" x=\"229.290368554\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.30978193\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.608498121162;stroke:#000000;stroke-opacity:0.608498121162;\" x=\"185.755762794\" xlink:href=\"#C0_0_3af6fb4475\" y=\"141.123461393\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.719939839089;stroke:#000000;stroke-opacity:0.719939839089;\" x=\"248.663219272\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.931611245\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.775256127325;stroke:#000000;stroke-opacity:0.775256127325;\" x=\"226.062156413\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.744539756\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.62040980504;stroke:#000000;stroke-opacity:0.62040980504;\" x=\"202.961347757\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.118804162\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.728868964547;stroke:#000000;stroke-opacity:0.728868964547;\" x=\"209.35789789\" xlink:href=\"#C0_0_3af6fb4475\" y=\"160.269465271\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.776372076461;stroke:#000000;stroke-opacity:0.776372076461;\" x=\"217.985953188\" xlink:href=\"#C0_0_3af6fb4475\" y=\"150.074410171\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.823459529127;stroke:#000000;stroke-opacity:0.823459529127;\" x=\"203.465802688\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.833134742\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.46748012017;stroke:#000000;stroke-opacity:0.46748012017;\" x=\"171.457735921\" xlink:href=\"#C0_0_3af6fb4475\" y=\"136.395853227\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.5651792709;stroke:#000000;stroke-opacity:0.5651792709;\" x=\"222.818365757\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.106899864\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.636353630085;stroke:#000000;stroke-opacity:0.636353630085;\" x=\"236.398624453\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.023583375\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.763407404232;stroke:#000000;stroke-opacity:0.763407404232;\" x=\"225.350655017\" xlink:href=\"#C0_0_3af6fb4475\" y=\"169.165116602\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.625803559685;stroke:#000000;stroke-opacity:0.625803559685;\" x=\"223.828378572\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.172637022\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.948444985438;stroke:#000000;stroke-opacity:0.948444985438;\" x=\"202.131917324\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.81675037\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.949511394278;stroke:#000000;stroke-opacity:0.949511394278;\" x=\"226.852731896\" xlink:href=\"#C0_0_3af6fb4475\" y=\"183.339496655\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.983930451914;stroke:#000000;stroke-opacity:0.983930451914;\" x=\"235.731484093\" xlink:href=\"#C0_0_3af6fb4475\" y=\"192.486045183\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.783755762814;stroke:#000000;stroke-opacity:0.783755762814;\" x=\"185.332131348\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.813074742\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.533858562528;stroke:#000000;stroke-opacity:0.533858562528;\" x=\"183.016816487\" xlink:href=\"#C0_0_3af6fb4475\" y=\"139.954392877\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.825095414682;stroke:#000000;stroke-opacity:0.825095414682;\" x=\"226.361765281\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.06051986\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.553082828144;stroke:#000000;stroke-opacity:0.553082828144;\" x=\"195.278382167\" xlink:href=\"#C0_0_3af6fb4475\" y=\"158.133498991\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.606260521926;stroke:#000000;stroke-opacity:0.606260521926;\" x=\"176.621067967\" xlink:href=\"#C0_0_3af6fb4475\" y=\"180.804925896\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.936439320971;stroke:#000000;stroke-opacity:0.936439320971;\" x=\"222.151547529\" xlink:href=\"#C0_0_3af6fb4475\" y=\"187.70942809\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.835489984221;stroke:#000000;stroke-opacity:0.835489984221;\" x=\"228.209532012\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.471102531\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.857963118381;stroke:#000000;stroke-opacity:0.857963118381;\" x=\"183.146141465\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.609059221\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.639038714427;stroke:#000000;stroke-opacity:0.639038714427;\" x=\"177.127582802\" xlink:href=\"#C0_0_3af6fb4475\" y=\"151.686110634\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.867698769931;stroke:#000000;stroke-opacity:0.867698769931;\" x=\"238.472029651\" xlink:href=\"#C0_0_3af6fb4475\" y=\"173.015276244\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.59852923519;stroke:#000000;stroke-opacity:0.59852923519;\" x=\"230.410359989\" xlink:href=\"#C0_0_3af6fb4475\" y=\"169.433280725\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.781208986649;stroke:#000000;stroke-opacity:0.781208986649;\" x=\"221.249084252\" xlink:href=\"#C0_0_3af6fb4475\" y=\"162.910806143\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.957986130633;stroke:#000000;stroke-opacity:0.957986130633;\" x=\"196.465379085\" xlink:href=\"#C0_0_3af6fb4475\" y=\"194.73321031\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.782673928793;stroke:#000000;stroke-opacity:0.782673928793;\" x=\"198.472924038\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.062815175\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.955175915704;stroke:#000000;stroke-opacity:0.955175915704;\" x=\"196.719864066\" xlink:href=\"#C0_0_3af6fb4475\" y=\"181.667161172\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.981833578137;stroke:#000000;stroke-opacity:0.981833578137;\" x=\"184.56019717\" xlink:href=\"#C0_0_3af6fb4475\" y=\"179.511038825\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.730107848967;stroke:#000000;stroke-opacity:0.730107848967;\" x=\"184.16702911\" xlink:href=\"#C0_0_3af6fb4475\" y=\"155.62977856\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.946904803498;stroke:#000000;stroke-opacity:0.946904803498;\" x=\"205.816399399\" xlink:href=\"#C0_0_3af6fb4475\" y=\"195.140432851\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.890030015296;stroke:#000000;stroke-opacity:0.890030015296;\" x=\"196.33871082\" xlink:href=\"#C0_0_3af6fb4475\" y=\"171.77537141\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.928370753744;stroke:#000000;stroke-opacity:0.928370753744;\" x=\"189.192724621\" xlink:href=\"#C0_0_3af6fb4475\" y=\"199.634372206\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.940498946913;stroke:#000000;stroke-opacity:0.940498946913;\" x=\"192.779401706\" xlink:href=\"#C0_0_3af6fb4475\" y=\"200.564080231\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.93320706073;stroke:#000000;stroke-opacity:0.93320706073;\" x=\"182.233951271\" xlink:href=\"#C0_0_3af6fb4475\" y=\"147.744869915\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.907538054206;stroke:#000000;stroke-opacity:0.907538054206;\" x=\"197.020967395\" xlink:href=\"#C0_0_3af6fb4475\" y=\"196.71967208\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.939585839277;stroke:#000000;stroke-opacity:0.939585839277;\" x=\"192.148977334\" xlink:href=\"#C0_0_3af6fb4475\" y=\"200.493244625\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.918327066184;stroke:#000000;stroke-opacity:0.918327066184;\" x=\"130.525957143\" xlink:href=\"#C0_0_3af6fb4475\" y=\"104.001438939\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.982785218038;stroke:#000000;stroke-opacity:0.982785218038;\" x=\"121.15357209\" xlink:href=\"#C0_0_3af6fb4475\" y=\"106.921573828\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.785473955568;stroke:#000000;stroke-opacity:0.785473955568;\" x=\"146.268035117\" xlink:href=\"#C0_0_3af6fb4475\" y=\"110.537902282\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.397545779387;stroke:#000000;stroke-opacity:0.397545779387;\" x=\"182.446840301\" xlink:href=\"#C0_0_3af6fb4475\" y=\"144.795361399\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.987540221797;stroke:#000000;stroke-opacity:0.987540221797;\" x=\"126.133944619\" xlink:href=\"#C0_0_3af6fb4475\" y=\"116.897300484\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.984815829782;stroke:#000000;stroke-opacity:0.984815829782;\" x=\"123.565366744\" xlink:href=\"#C0_0_3af6fb4475\" y=\"115.042980615\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.508514931884;stroke:#000000;stroke-opacity:0.508514931884;\" x=\"193.563630107\" xlink:href=\"#C0_0_3af6fb4475\" y=\"142.364927426\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.882387894084;stroke:#000000;stroke-opacity:0.882387894084;\" x=\"175.926394643\" xlink:href=\"#C0_0_3af6fb4475\" y=\"167.078168348\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.718021972041;stroke:#000000;stroke-opacity:0.718021972041;\" x=\"232.987906504\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.846139002\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.680403179319;stroke:#000000;stroke-opacity:0.680403179319;\" x=\"212.562247989\" xlink:href=\"#C0_0_3af6fb4475\" y=\"149.548389209\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.876979689275;stroke:#000000;stroke-opacity:0.876979689275;\" x=\"220.215595625\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.291083761\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.933268673604;stroke:#000000;stroke-opacity:0.933268673604;\" x=\"226.737083537\" xlink:href=\"#C0_0_3af6fb4475\" y=\"187.08558707\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.571828542166;stroke:#000000;stroke-opacity:0.571828542166;\" x=\"188.139812968\" xlink:href=\"#C0_0_3af6fb4475\" y=\"166.802244439\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.634416160404;stroke:#000000;stroke-opacity:0.634416160404;\" x=\"234.419854736\" xlink:href=\"#C0_0_3af6fb4475\" y=\"164.407007004\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.578977791386;stroke:#000000;stroke-opacity:0.578977791386;\" x=\"232.749156911\" xlink:href=\"#C0_0_3af6fb4475\" y=\"168.207457715\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.676770239104;stroke:#000000;stroke-opacity:0.676770239104;\" x=\"222.899993204\" xlink:href=\"#C0_0_3af6fb4475\" y=\"168.203010208\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.740418696758;stroke:#000000;stroke-opacity:0.740418696758;\" x=\"239.478519574\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.376763161\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.599481271305;stroke:#000000;stroke-opacity:0.599481271305;\" x=\"214.050281841\" xlink:href=\"#C0_0_3af6fb4475\" y=\"163.902685721\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.910214155824;stroke:#000000;stroke-opacity:0.910214155824;\" x=\"189.525657635\" xlink:href=\"#C0_0_3af6fb4475\" y=\"170.062124098\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.977055087719;stroke:#000000;stroke-opacity:0.977055087719;\" x=\"235.813720382\" xlink:href=\"#C0_0_3af6fb4475\" y=\"191.832526844\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.810881498848;stroke:#000000;stroke-opacity:0.810881498848;\" x=\"220.957163693\" xlink:href=\"#C0_0_3af6fb4475\" y=\"171.03408013\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.873237109346;stroke:#000000;stroke-opacity:0.873237109346;\" x=\"237.759764811\" xlink:href=\"#C0_0_3af6fb4475\" y=\"171.078343108\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.726694586268;stroke:#000000;stroke-opacity:0.726694586268;\" x=\"248.946384811\" xlink:href=\"#C0_0_3af6fb4475\" y=\"174.68911246\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.697036429899;stroke:#000000;stroke-opacity:0.697036429899;\" x=\"247.718836442\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.111094818\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.876694882601;stroke:#000000;stroke-opacity:0.876694882601;\" x=\"191.895130278\" xlink:href=\"#C0_0_3af6fb4475\" y=\"146.848412469\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.879012012412;stroke:#000000;stroke-opacity:0.879012012412;\" x=\"240.330993218\" xlink:href=\"#C0_0_3af6fb4475\" y=\"172.466011003\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;stroke:#000000;\" x=\"236.70477577\" xlink:href=\"#C0_0_3af6fb4475\" y=\"188.785649661\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.81967590981;stroke:#000000;stroke-opacity:0.81967590981;\" x=\"222.074597426\" xlink:href=\"#C0_0_3af6fb4475\" y=\"175.123987977\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.842579398884;stroke:#000000;stroke-opacity:0.842579398884;\" x=\"239.58471865\" xlink:href=\"#C0_0_3af6fb4475\" y=\"176.366104986\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.974844830044;stroke:#000000;stroke-opacity:0.974844830044;\" x=\"238.171310206\" xlink:href=\"#C0_0_3af6fb4475\" y=\"189.655426464\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.99156914704;stroke:#000000;stroke-opacity:0.99156914704;\" x=\"236.962116265\" xlink:href=\"#C0_0_3af6fb4475\" y=\"192.838149353\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.947828701935;stroke:#000000;stroke-opacity:0.947828701935;\" x=\"222.496938301\" xlink:href=\"#C0_0_3af6fb4475\" y=\"175.987847341\"/>\n",
+       "    </g>\n",
+       "    <g clip-path=\"url(#p1650f2cb30)\">\n",
+       "     <use style=\"fill:#0000ff;fill-opacity:0.929141309754;stroke:#000000;stroke-opacity:0.929141309754;\" x=\"241.959698125\" xlink:href=\"#C0_0_3af6fb4475\" y=\"187.310996736\"/>\n",
+       "    </g>\n",
+       "   </g>\n",
+       "  </g>\n",
+       " </g>\n",
+       " <defs>\n",
+       "  <clipPath id=\"p1650f2cb30\">\n",
+       "   <rect height=\"324.0\" width=\"345.6\" x=\"7.2\" y=\"7.2\"/>\n",
+       "  </clipPath>\n",
+       " </defs>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "<skbio._base.OrdinationResults at 0x10ca97f60>"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "coordinates"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "from emperor import Emperor"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "\n",
+       "if ($(\"#emperor-css\").length == 0){{\n",
+       "    $(\"head\").append([\n",
+       "\n",
+       "        '<link id=\"emperor-css\" rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/css/emperor.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/jquery-ui.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/slick.grid.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/spectrum.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/chosen.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/jquery.contextMenu.min.css\">'\n",
+       "    ]);\n",
+       "}}\n",
+       "</script>\n",
+       "\n",
+       "<div id='emperor-notebook-0x69a3643a' style=\"position: relative; width:100%; height:500px;\">\n",
+       "  <div class='loading' style=\"position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px\"><img src='/nbextensions/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in /nbextensions/emperor/support_files'></div>\n",
+       "</div>\n",
+       "</div>\n",
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "requirejs.config({\n",
+       "// the left side is the module name, and the right side is the path\n",
+       "// relative to the baseUrl attribute, do NOT include the .js extension\n",
+       "'paths': {\n",
+       "  /* jQuery */\n",
+       "  'jquery': '/nbextensions/emperor/support_files/vendor/js/jquery-2.1.4.min',\n",
+       "  'jqueryui': '/nbextensions/emperor/support_files/vendor/js/jquery-ui.min',\n",
+       "  'jquery_drag': '/nbextensions/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',\n",
+       "\n",
+       "  /* jQuery plugins */\n",
+       "  'chosen': '/nbextensions/emperor/support_files/vendor/js/chosen.jquery.min',\n",
+       "  'spectrum': '/nbextensions/emperor/support_files/vendor/js/spectrum.min',\n",
+       "  'position': '/nbextensions/emperor/support_files/vendor/js/jquery.ui.position.min',\n",
+       "  'contextmenu': '/nbextensions/emperor/support_files/vendor/js/jquery.contextMenu.min',\n",
+       "\n",
+       "  /* other libraries */\n",
+       "  'underscore': '/nbextensions/emperor/support_files/vendor/js/underscore-min',\n",
+       "  'chroma': '/nbextensions/emperor/support_files/vendor/js/chroma.min',\n",
+       "  'filesaver': '/nbextensions/emperor/support_files/vendor/js/FileSaver.min',\n",
+       "  'blob': '/nbextensions/emperor/support_files/vendor/js/Blob',\n",
+       "  'd3': '/nbextensions/emperor/support_files/vendor/js/d3.min',\n",
+       "\n",
+       "\n",
+       "  /* THREE.js and plugins */\n",
+       "  'three': '/nbextensions/emperor/support_files/vendor/js/three.min',\n",
+       "  'orbitcontrols': '/nbextensions/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',\n",
+       "\n",
+       "  /* SlickGrid */\n",
+       "  'slickcore': '/nbextensions/emperor/support_files/vendor/js/slick.core.min',\n",
+       "  'slickgrid': '/nbextensions/emperor/support_files/vendor/js/slick.grid.min',\n",
+       "  'slickformatters': '/nbextensions/emperor/support_files/vendor/js/slick.editors.min',\n",
+       "  'slickeditors': '/nbextensions/emperor/support_files/vendor/js/slick.formatters.min',\n",
+       "\n",
+       "  /* Emperor's objects */\n",
+       "  'util': '/nbextensions/emperor/support_files/js/util',\n",
+       "  'model': '/nbextensions/emperor/support_files/js/model',\n",
+       "  'view': '/nbextensions/emperor/support_files/js/view',\n",
+       "  'controller': '/nbextensions/emperor/support_files/js/controller',\n",
+       "  'draw': '/nbextensions/emperor/support_files/js/draw',\n",
+       "  'scene3d': '/nbextensions/emperor/support_files/js/sceneplotview3d',\n",
+       "  'viewcontroller': '/nbextensions/emperor/support_files/js/view-controller',\n",
+       "  'colorviewcontroller': '/nbextensions/emperor/support_files/js/color-view-controller',\n",
+       "  'visibilitycontroller': '/nbextensions/emperor/support_files/js/visibility-controller',\n",
+       "  'scaleviewcontroller': '/nbextensions/emperor/support_files/js/scale-view-controller',\n",
+       "  'shapecontroller': '/nbextensions/emperor/support_files/js/shape-controller',\n",
+       "  'axescontroller': '/nbextensions/emperor/support_files/js/axes-controller',\n",
+       "  'shape-editor': '/nbextensions/emperor/support_files/js/shape-editor',\n",
+       "  'color-editor': '/nbextensions/emperor/support_files/js/color-editor',\n",
+       "  'scale-editor': '/nbextensions/emperor/support_files/js/scale-editor',\n",
+       "  'shapes': '/nbextensions/emperor/support_files/js/shapes'\n",
+       "},\n",
+       "/*\n",
+       "   Libraries that are not AMD compatible need shim to declare their\n",
+       "   dependencies.\n",
+       " */\n",
+       "'shim': {\n",
+       "  'jquery_drag': {\n",
+       "    'deps': ['jquery', 'jqueryui']\n",
+       "  },\n",
+       "  'chosen': {\n",
+       "    'deps': ['jquery'],\n",
+       "    'exports': 'jQuery.fn.chosen'\n",
+       "  },\n",
+       "  'contextmenu' : {\n",
+       "    'deps': ['jquery', 'jqueryui', 'position']\n",
+       "  },\n",
+       "  'filesaver' : {\n",
+       "    'deps': ['blob']\n",
+       "  },\n",
+       "  'orbitcontrols': {\n",
+       "    'deps': ['three']\n",
+       "  },\n",
+       "'slickcore': ['jqueryui'],\n",
+       "'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',\n",
+       "              'slickeditors']\n",
+       "}\n",
+       "});\n",
+       "\n",
+       "requirejs(\n",
+       "[\"jquery\", \"model\", \"controller\"],\n",
+       "function($, model, EmperorController) {\n",
+       "  var DecompositionModel = model.DecompositionModel;\n",
+       "\n",
+       "  var div = $('#emperor-notebook-0x69a3643a');\n",
+       "\n",
+       "  var ids = ['449.F21Plml', '449.M22Pinr', '449.M11Glns', '449.F33Fotr', '449.M54Plml', '449.F32Fotl', '449.M22Plml', '449.M24Fotl', '449.M21Glns', '449.M21Plmr', '449.M23Knee', '449.M43Plmr', '449.M63Plmr', '449.M64Plml', '449.F23Plml', '449.M44Plml', '449.F23Plmr', '449.M23Nost', '449.M54Plmr', '449.M53Plml', '449.M44Plmr', '449.M43Plml', '449.M63Plml', '449.M53Fotr', '449.F14Plmr', '449.F24Plmr', '449.M31Plmr', '449.F22Knel', '449.M31Knel', '449.F22Mout', '449.F21Navl', '449.F [...]
+       "  var coords = [[-0.179510749191, 0.160900395023, -0.00570965213906, 0.122334439759, -0.0162248971994], [0.0228821893392, 0.126741711638, 0.0271440495268, -0.127739135345, -0.0655730666726], [0.183540331585, 0.0665827817047, 0.0149981843457, -0.180790814272, 0.0458596183358], [-0.189814777693, 0.14904689444, -0.138100278244, 0.239620556398, 0.028344444461], [-0.205173121754, 0.114582609172, 0.0398627555447, 0.07244766104, -0.0215930402801], [-0.124142214882, 0.197819584616, -0.12 [...]
+       "  var pct_var = [12.2074583847, 10.0247517917, 8.60483771442, 3.9847746522699996, 2.91478655472];\n",
+       "  var md_headers = ['SampleID', 'BarcodeSequence', 'LinkerPrimerSequence', 'barcode_read_group_tag', 'dna_extracted_prep', 'experiment_alias', 'experiment_center', 'experiment_design_description', 'experiment_title', 'key_seq', 'library_construction_protocol', 'linker', 'nucl_acid_amp', 'nucl_acid_ext', 'pcr_cond', 'pcr_primers', 'physical_specimen_remaining_prep', 'platform', 'pool_member_name', 'pool_proportion', 'primer_read_group_tag', 'region', 'run_alias', 'run_center', 'ru [...]
+       "  var metadata = [['449.F21Plml', 'ATGCACTGGCGA', 'CATGCTGCCTCCCGTAGGAGT', 'F21Plml', 'True', 'CostelloWholeBodySites', 'CCME', 'Healthy adults were recruited to donate samples on two consecutive days in June and again three months later on two consecutive days in September 2008. Volunteers were unrelated individuals of both sexes and most lived in Boulder, CO. Female subjects F1, F2, F3 and male subjects M1, M2, M3, M4, and M6 were 30-35 years old. Subject M5 was approximately 6 [...]
+       "  var axesNames = [0, 1, 2, 3, 4];\n",
+       "\n",
+       "  var dm, ec;\n",
+       "\n",
+       "  function init() {\n",
+       "    // Initialize the DecompositionModel\n",
+       "    dm = new DecompositionModel(name, ids, coords, pct_var,\n",
+       "                                md_headers, metadata, axesNames);\n",
+       "    // Initialize the EmperorController\n",
+       "    ec = new EmperorController(dm, 'emperor-notebook-0x69a3643a');\n",
+       "  }\n",
+       "\n",
+       "  function animate() {\n",
+       "    requestAnimationFrame(animate);\n",
+       "    ec.render();\n",
+       "  }\n",
+       "  $(window).resize(function() {\n",
+       "    ec.resize(div.innerWidth(), div.innerHeight());\n",
+       "  });\n",
+       "\n",
+       "  $(function(){\n",
+       "    init();\n",
+       "    animate();\n",
+       "\n",
+       "  });\n",
+       "\n",
+       "}); // END REQUIRE.JS block\n",
+       "</script>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<emperor.core.Emperor at 0x1176da710>"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "Emperor(coordinates, metadata, remote=False)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "-"
+    }
+   },
+   "source": [
+    "<!-- RISE has some scrolling bugs, so we pre-allocate some space to display the emperor plot -->\n",
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- ~~Background (why $\\beta$-diversity).~~\n",
+    "\n",
+    "- **What is Emperor.**\n",
+    "\n",
+    "- How can we use Emperor.\n",
+    "    \n",
+    "- Analyzing a use case."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# What is Emperor?\n",
+    "\n",
+    "- A Python 2/3 package that powers a JavaScript UI.\n",
+    "    - https://github.com/biocore/emperor\n",
+    "    \n",
+    "- Originated in the context of Quantitative Insights Into Microbial Ecology http://2.qiime.org"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Scatter plot viewer.\n",
+    "\n",
+    "    - Visualize\n",
+    "    - Interact\n",
+    "    - Share"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Other applications"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Qiita\n",
+    "    - https://qiita.ucsd.edu\n",
+    "    ![qiita](https://raw.githubusercontent.com/biocore/qiita/master/qiita_pet/static/img/logo.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- American Gut (participant's results).\n",
+    "    - http://americangut.org/\n",
+    "    <img src='https://lh4.googleusercontent.com/88tkWe8K-u_ZUgO3GVIrnDSeJE65QGHOlCY_-WQ3mFxmmskkxEZGEmj6GxYilVe5f5gnEx2K_EdOZngTeY750V4rtNLt0n5rVA6pj1ow9oFHltwYlbQ' style='height:80px'></img>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Illumina's BaseSpace processing results for the QIIME app.\n",
+    "- Metabolomic analysis, IPython notebook ..."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "    ... kinda"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Kinda?\n",
+    "\n",
+    "- https://github.com/jupyter/nbviewer/issues/316\n",
+    "\n",
+    "<img src='./images/glitch.gif' style='height:500px;'>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Nowadays"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Python API.\n",
+    "    - Python 2 and 3.\n",
+    "    - Integration with scikit-bio.\n",
+    "    - Jupyter integration.\n",
+    "    - Pandas 🐼 Integration."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- JavaScript API."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Command Line Interface (powered by QIIME 2)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- ~~Background (why $\\beta$-diversity).~~\n",
+    "\n",
+    "- ~~What is Emperor.~~\n",
+    "\n",
+    "- **How can we use Emperor**.\n",
+    "    \n",
+    "- Analyzing a use case."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Python"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "- 1 main class `Emperor`, depends on `scikit-bio` and `pandas`.\n",
+    "\n",
+    "- Format Python data into JSON and display it using JavaScript."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "from emperor import Emperor\n",
+    "\n",
+    "Emperor?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# http://emperor.microbio.me/uno/\n",
+    "\n",
+    "![emperor](./images/main-doc.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# http://emperor.microbio.me/uno/\n",
+    "\n",
+    "![emperor](./images/python-doc.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# http://emperor.microbio.me/uno/\n",
+    "\n",
+    "![emperor](./images/python-doc-2.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# 🐼s integration - experimental"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import pandas as pd"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "df = pd.read_csv('./tips.csv')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>total_bill</th>\n",
+       "      <th>tip</th>\n",
+       "      <th>sex</th>\n",
+       "      <th>smoker</th>\n",
+       "      <th>day</th>\n",
+       "      <th>time</th>\n",
+       "      <th>size</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>0</th>\n",
+       "      <td>16.99</td>\n",
+       "      <td>1.01</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>1</th>\n",
+       "      <td>10.34</td>\n",
+       "      <td>1.66</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>2</th>\n",
+       "      <td>21.01</td>\n",
+       "      <td>3.50</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>3</th>\n",
+       "      <td>23.68</td>\n",
+       "      <td>3.31</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>4</th>\n",
+       "      <td>24.59</td>\n",
+       "      <td>3.61</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>5</th>\n",
+       "      <td>25.29</td>\n",
+       "      <td>4.71</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>6</th>\n",
+       "      <td>8.77</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>7</th>\n",
+       "      <td>26.88</td>\n",
+       "      <td>3.12</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>8</th>\n",
+       "      <td>15.04</td>\n",
+       "      <td>1.96</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>9</th>\n",
+       "      <td>14.78</td>\n",
+       "      <td>3.23</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>10</th>\n",
+       "      <td>10.27</td>\n",
+       "      <td>1.71</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>11</th>\n",
+       "      <td>35.26</td>\n",
+       "      <td>5.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12</th>\n",
+       "      <td>15.42</td>\n",
+       "      <td>1.57</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>13</th>\n",
+       "      <td>18.43</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>14</th>\n",
+       "      <td>14.83</td>\n",
+       "      <td>3.02</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>15</th>\n",
+       "      <td>21.58</td>\n",
+       "      <td>3.92</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>16</th>\n",
+       "      <td>10.33</td>\n",
+       "      <td>1.67</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>17</th>\n",
+       "      <td>16.29</td>\n",
+       "      <td>3.71</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>18</th>\n",
+       "      <td>16.97</td>\n",
+       "      <td>3.50</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sun</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>19</th>\n",
+       "      <td>20.65</td>\n",
+       "      <td>3.35</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>20</th>\n",
+       "      <td>17.92</td>\n",
+       "      <td>4.08</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>21</th>\n",
+       "      <td>20.29</td>\n",
+       "      <td>2.75</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>22</th>\n",
+       "      <td>15.77</td>\n",
+       "      <td>2.23</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>23</th>\n",
+       "      <td>39.42</td>\n",
+       "      <td>7.58</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>24</th>\n",
+       "      <td>19.82</td>\n",
+       "      <td>3.18</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>25</th>\n",
+       "      <td>17.81</td>\n",
+       "      <td>2.34</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>26</th>\n",
+       "      <td>13.37</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>27</th>\n",
+       "      <td>12.69</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>28</th>\n",
+       "      <td>21.70</td>\n",
+       "      <td>4.30</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>29</th>\n",
+       "      <td>19.65</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>...</th>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>214</th>\n",
+       "      <td>28.17</td>\n",
+       "      <td>6.50</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>215</th>\n",
+       "      <td>12.90</td>\n",
+       "      <td>1.10</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>216</th>\n",
+       "      <td>28.15</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>5</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>217</th>\n",
+       "      <td>11.59</td>\n",
+       "      <td>1.50</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>218</th>\n",
+       "      <td>7.74</td>\n",
+       "      <td>1.44</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>219</th>\n",
+       "      <td>30.14</td>\n",
+       "      <td>3.09</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>220</th>\n",
+       "      <td>12.16</td>\n",
+       "      <td>2.20</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>221</th>\n",
+       "      <td>13.42</td>\n",
+       "      <td>3.48</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>222</th>\n",
+       "      <td>8.58</td>\n",
+       "      <td>1.92</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>1</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>223</th>\n",
+       "      <td>15.98</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>224</th>\n",
+       "      <td>13.42</td>\n",
+       "      <td>1.58</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>225</th>\n",
+       "      <td>16.27</td>\n",
+       "      <td>2.50</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>226</th>\n",
+       "      <td>10.09</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Fri</td>\n",
+       "      <td>Lunch</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>227</th>\n",
+       "      <td>20.45</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>228</th>\n",
+       "      <td>13.28</td>\n",
+       "      <td>2.72</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>229</th>\n",
+       "      <td>22.12</td>\n",
+       "      <td>2.88</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>230</th>\n",
+       "      <td>24.01</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>231</th>\n",
+       "      <td>15.69</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>232</th>\n",
+       "      <td>11.61</td>\n",
+       "      <td>3.39</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>233</th>\n",
+       "      <td>10.77</td>\n",
+       "      <td>1.47</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>234</th>\n",
+       "      <td>15.53</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>235</th>\n",
+       "      <td>10.07</td>\n",
+       "      <td>1.25</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>236</th>\n",
+       "      <td>12.60</td>\n",
+       "      <td>1.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>237</th>\n",
+       "      <td>32.83</td>\n",
+       "      <td>1.17</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>238</th>\n",
+       "      <td>35.83</td>\n",
+       "      <td>4.67</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>239</th>\n",
+       "      <td>29.03</td>\n",
+       "      <td>5.92</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>240</th>\n",
+       "      <td>27.18</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>241</th>\n",
+       "      <td>22.67</td>\n",
+       "      <td>2.00</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>Yes</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>242</th>\n",
+       "      <td>17.82</td>\n",
+       "      <td>1.75</td>\n",
+       "      <td>Male</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Sat</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>243</th>\n",
+       "      <td>18.78</td>\n",
+       "      <td>3.00</td>\n",
+       "      <td>Female</td>\n",
+       "      <td>No</td>\n",
+       "      <td>Thur</td>\n",
+       "      <td>Dinner</td>\n",
+       "      <td>2</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "<p>244 rows × 7 columns</p>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "     total_bill   tip     sex smoker   day    time  size\n",
+       "0         16.99  1.01  Female     No   Sun  Dinner     2\n",
+       "1         10.34  1.66    Male     No   Sun  Dinner     3\n",
+       "2         21.01  3.50    Male     No   Sun  Dinner     3\n",
+       "3         23.68  3.31    Male     No   Sun  Dinner     2\n",
+       "4         24.59  3.61  Female     No   Sun  Dinner     4\n",
+       "5         25.29  4.71    Male     No   Sun  Dinner     4\n",
+       "6          8.77  2.00    Male     No   Sun  Dinner     2\n",
+       "7         26.88  3.12    Male     No   Sun  Dinner     4\n",
+       "8         15.04  1.96    Male     No   Sun  Dinner     2\n",
+       "9         14.78  3.23    Male     No   Sun  Dinner     2\n",
+       "10        10.27  1.71    Male     No   Sun  Dinner     2\n",
+       "11        35.26  5.00  Female     No   Sun  Dinner     4\n",
+       "12        15.42  1.57    Male     No   Sun  Dinner     2\n",
+       "13        18.43  3.00    Male     No   Sun  Dinner     4\n",
+       "14        14.83  3.02  Female     No   Sun  Dinner     2\n",
+       "15        21.58  3.92    Male     No   Sun  Dinner     2\n",
+       "16        10.33  1.67  Female     No   Sun  Dinner     3\n",
+       "17        16.29  3.71    Male     No   Sun  Dinner     3\n",
+       "18        16.97  3.50  Female     No   Sun  Dinner     3\n",
+       "19        20.65  3.35    Male     No   Sat  Dinner     3\n",
+       "20        17.92  4.08    Male     No   Sat  Dinner     2\n",
+       "21        20.29  2.75  Female     No   Sat  Dinner     2\n",
+       "22        15.77  2.23  Female     No   Sat  Dinner     2\n",
+       "23        39.42  7.58    Male     No   Sat  Dinner     4\n",
+       "24        19.82  3.18    Male     No   Sat  Dinner     2\n",
+       "25        17.81  2.34    Male     No   Sat  Dinner     4\n",
+       "26        13.37  2.00    Male     No   Sat  Dinner     2\n",
+       "27        12.69  2.00    Male     No   Sat  Dinner     2\n",
+       "28        21.70  4.30    Male     No   Sat  Dinner     2\n",
+       "29        19.65  3.00  Female     No   Sat  Dinner     2\n",
+       "..          ...   ...     ...    ...   ...     ...   ...\n",
+       "214       28.17  6.50  Female    Yes   Sat  Dinner     3\n",
+       "215       12.90  1.10  Female    Yes   Sat  Dinner     2\n",
+       "216       28.15  3.00    Male    Yes   Sat  Dinner     5\n",
+       "217       11.59  1.50    Male    Yes   Sat  Dinner     2\n",
+       "218        7.74  1.44    Male    Yes   Sat  Dinner     2\n",
+       "219       30.14  3.09  Female    Yes   Sat  Dinner     4\n",
+       "220       12.16  2.20    Male    Yes   Fri   Lunch     2\n",
+       "221       13.42  3.48  Female    Yes   Fri   Lunch     2\n",
+       "222        8.58  1.92    Male    Yes   Fri   Lunch     1\n",
+       "223       15.98  3.00  Female     No   Fri   Lunch     3\n",
+       "224       13.42  1.58    Male    Yes   Fri   Lunch     2\n",
+       "225       16.27  2.50  Female    Yes   Fri   Lunch     2\n",
+       "226       10.09  2.00  Female    Yes   Fri   Lunch     2\n",
+       "227       20.45  3.00    Male     No   Sat  Dinner     4\n",
+       "228       13.28  2.72    Male     No   Sat  Dinner     2\n",
+       "229       22.12  2.88  Female    Yes   Sat  Dinner     2\n",
+       "230       24.01  2.00    Male    Yes   Sat  Dinner     4\n",
+       "231       15.69  3.00    Male    Yes   Sat  Dinner     3\n",
+       "232       11.61  3.39    Male     No   Sat  Dinner     2\n",
+       "233       10.77  1.47    Male     No   Sat  Dinner     2\n",
+       "234       15.53  3.00    Male    Yes   Sat  Dinner     2\n",
+       "235       10.07  1.25    Male     No   Sat  Dinner     2\n",
+       "236       12.60  1.00    Male    Yes   Sat  Dinner     2\n",
+       "237       32.83  1.17    Male    Yes   Sat  Dinner     2\n",
+       "238       35.83  4.67  Female     No   Sat  Dinner     3\n",
+       "239       29.03  5.92    Male     No   Sat  Dinner     3\n",
+       "240       27.18  2.00  Female    Yes   Sat  Dinner     2\n",
+       "241       22.67  2.00    Male    Yes   Sat  Dinner     2\n",
+       "242       17.82  1.75    Male     No   Sat  Dinner     2\n",
+       "243       18.78  3.00  Female     No  Thur  Dinner     2\n",
+       "\n",
+       "[244 rows x 7 columns]"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "df"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# 🐼s integration - experimental"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "- Coordinates are inferred from the numerical data, see additional `x`, `y` and `z` parameters."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "\n",
+       "if ($(\"#emperor-css\").length == 0){{\n",
+       "    $(\"head\").append([\n",
+       "\n",
+       "        '<link id=\"emperor-css\" rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/css/emperor.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/jquery-ui.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/slick.grid.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/spectrum.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/chosen.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"/nbextensions/emperor/support_files/vendor/css/jquery.contextMenu.min.css\">'\n",
+       "    ]);\n",
+       "}}\n",
+       "</script>\n",
+       "\n",
+       "<div id='emperor-notebook-0xc5a5f7a5' style=\"position: relative; width:100%; height:500px;\">\n",
+       "  <div class='loading' style=\"position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px\"><img src='/nbextensions/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in /nbextensions/emperor/support_files'></div>\n",
+       "</div>\n",
+       "</div>\n",
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "requirejs.config({\n",
+       "// the left side is the module name, and the right side is the path\n",
+       "// relative to the baseUrl attribute, do NOT include the .js extension\n",
+       "'paths': {\n",
+       "  /* jQuery */\n",
+       "  'jquery': '/nbextensions/emperor/support_files/vendor/js/jquery-2.1.4.min',\n",
+       "  'jqueryui': '/nbextensions/emperor/support_files/vendor/js/jquery-ui.min',\n",
+       "  'jquery_drag': '/nbextensions/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',\n",
+       "\n",
+       "  /* jQuery plugins */\n",
+       "  'chosen': '/nbextensions/emperor/support_files/vendor/js/chosen.jquery.min',\n",
+       "  'spectrum': '/nbextensions/emperor/support_files/vendor/js/spectrum.min',\n",
+       "  'position': '/nbextensions/emperor/support_files/vendor/js/jquery.ui.position.min',\n",
+       "  'contextmenu': '/nbextensions/emperor/support_files/vendor/js/jquery.contextMenu.min',\n",
+       "\n",
+       "  /* other libraries */\n",
+       "  'underscore': '/nbextensions/emperor/support_files/vendor/js/underscore-min',\n",
+       "  'chroma': '/nbextensions/emperor/support_files/vendor/js/chroma.min',\n",
+       "  'filesaver': '/nbextensions/emperor/support_files/vendor/js/FileSaver.min',\n",
+       "  'blob': '/nbextensions/emperor/support_files/vendor/js/Blob',\n",
+       "  'd3': '/nbextensions/emperor/support_files/vendor/js/d3.min',\n",
+       "\n",
+       "\n",
+       "  /* THREE.js and plugins */\n",
+       "  'three': '/nbextensions/emperor/support_files/vendor/js/three.min',\n",
+       "  'orbitcontrols': '/nbextensions/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',\n",
+       "\n",
+       "  /* SlickGrid */\n",
+       "  'slickcore': '/nbextensions/emperor/support_files/vendor/js/slick.core.min',\n",
+       "  'slickgrid': '/nbextensions/emperor/support_files/vendor/js/slick.grid.min',\n",
+       "  'slickformatters': '/nbextensions/emperor/support_files/vendor/js/slick.editors.min',\n",
+       "  'slickeditors': '/nbextensions/emperor/support_files/vendor/js/slick.formatters.min',\n",
+       "\n",
+       "  /* Emperor's objects */\n",
+       "  'util': '/nbextensions/emperor/support_files/js/util',\n",
+       "  'model': '/nbextensions/emperor/support_files/js/model',\n",
+       "  'view': '/nbextensions/emperor/support_files/js/view',\n",
+       "  'controller': '/nbextensions/emperor/support_files/js/controller',\n",
+       "  'draw': '/nbextensions/emperor/support_files/js/draw',\n",
+       "  'scene3d': '/nbextensions/emperor/support_files/js/sceneplotview3d',\n",
+       "  'viewcontroller': '/nbextensions/emperor/support_files/js/view-controller',\n",
+       "  'colorviewcontroller': '/nbextensions/emperor/support_files/js/color-view-controller',\n",
+       "  'visibilitycontroller': '/nbextensions/emperor/support_files/js/visibility-controller',\n",
+       "  'scaleviewcontroller': '/nbextensions/emperor/support_files/js/scale-view-controller',\n",
+       "  'shapecontroller': '/nbextensions/emperor/support_files/js/shape-controller',\n",
+       "  'axescontroller': '/nbextensions/emperor/support_files/js/axes-controller',\n",
+       "  'shape-editor': '/nbextensions/emperor/support_files/js/shape-editor',\n",
+       "  'color-editor': '/nbextensions/emperor/support_files/js/color-editor',\n",
+       "  'scale-editor': '/nbextensions/emperor/support_files/js/scale-editor',\n",
+       "  'shapes': '/nbextensions/emperor/support_files/js/shapes'\n",
+       "},\n",
+       "/*\n",
+       "   Libraries that are not AMD compatible need shim to declare their\n",
+       "   dependencies.\n",
+       " */\n",
+       "'shim': {\n",
+       "  'jquery_drag': {\n",
+       "    'deps': ['jquery', 'jqueryui']\n",
+       "  },\n",
+       "  'chosen': {\n",
+       "    'deps': ['jquery'],\n",
+       "    'exports': 'jQuery.fn.chosen'\n",
+       "  },\n",
+       "  'contextmenu' : {\n",
+       "    'deps': ['jquery', 'jqueryui', 'position']\n",
+       "  },\n",
+       "  'filesaver' : {\n",
+       "    'deps': ['blob']\n",
+       "  },\n",
+       "  'orbitcontrols': {\n",
+       "    'deps': ['three']\n",
+       "  },\n",
+       "'slickcore': ['jqueryui'],\n",
+       "'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',\n",
+       "              'slickeditors']\n",
+       "}\n",
+       "});\n",
+       "\n",
+       "requirejs(\n",
+       "[\"jquery\", \"model\", \"controller\"],\n",
+       "function($, model, EmperorController) {\n",
+       "  var DecompositionModel = model.DecompositionModel;\n",
+       "\n",
+       "  var div = $('#emperor-notebook-0xc5a5f7a5');\n",
+       "\n",
+       "  var ids = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', ' [...]
+       "  var coords = [[0.334382995473332, 0.101, 0.3333333333333333], [0.2035032473922456, 0.16599999999999998, 0.5], [0.41350127927573316, 0.35, 0.5], [0.4660499901594174, 0.331, 0.3333333333333333], [0.48395985042314504, 0.361, 0.6666666666666666], [0.49773666601062777, 0.471, 0.6666666666666666], [0.17260381814603423, 0.2, 0.3333333333333333], [0.5290297185593387, 0.312, 0.6666666666666666], [0.29600472347962997, 0.196, 0.3333333333333333], [0.29088762054713635, 0.323, 0.33333333333 [...]
+       "  var pct_var = [7925.293861397826, 191.44546380624726, 90.45908385616922];\n",
+       "  var md_headers = ['#SampleID', 'total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'];\n",
+       "  var metadata = [['0', '16.99', '1.01', 'Female', 'No', 'Sun', 'Dinner', '2'], ['1', '10.34', '1.66', 'Male', 'No', 'Sun', 'Dinner', '3'], ['2', '21.01', '3.5', 'Male', 'No', 'Sun', 'Dinner', '3'], ['3', '23.68', '3.31', 'Male', 'No', 'Sun', 'Dinner', '2'], ['4', '24.59', '3.61', 'Female', 'No', 'Sun', 'Dinner', '4'], ['5', '25.29', '4.71', 'Male', 'No', 'Sun', 'Dinner', '4'], ['6', '8.77', '2.0', 'Male', 'No', 'Sun', 'Dinner', '2'], ['7', '26.88', '3.12', 'Male', 'No', 'Sun', ' [...]
+       "  var axesNames = ['total_bill', 'tip', 'size'];\n",
+       "\n",
+       "  var dm, ec;\n",
+       "\n",
+       "  function init() {\n",
+       "    // Initialize the DecompositionModel\n",
+       "    dm = new DecompositionModel(name, ids, coords, pct_var,\n",
+       "                                md_headers, metadata, axesNames);\n",
+       "    // Initialize the EmperorController\n",
+       "    ec = new EmperorController(dm, 'emperor-notebook-0xc5a5f7a5');\n",
+       "  }\n",
+       "\n",
+       "  function animate() {\n",
+       "    requestAnimationFrame(animate);\n",
+       "    ec.render();\n",
+       "  }\n",
+       "  $(window).resize(function() {\n",
+       "    ec.resize(div.innerWidth(), div.innerHeight());\n",
+       "  });\n",
+       "\n",
+       "  $(function(){\n",
+       "    init();\n",
+       "    animate();\n",
+       "\n",
+       "  });\n",
+       "\n",
+       "}); // END REQUIRE.JS block\n",
+       "</script>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<emperor.core.Emperor at 0x1176b74e0>"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "from emperor import scatterplot\n",
+    "scatterplot(df, remote=False)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- ~~Background (why $\\beta$-diversity).~~\n",
+    "\n",
+    "- ~~What is Emperor.~~\n",
+    "\n",
+    "- **How can we use Emperor.**\n",
+    "    \n",
+    "- Analyzing a use case."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Emperor and Jupyter 📓\n",
+    "\n",
+    "- nbviewer\n",
+    "    See the examples folder in our repo: https://github.com/biocore/emperor/tree/new-api/examples\n",
+    "\n",
+    "- Jupyter notebook\n",
+    "\n",
+    "- Standalone HTML plot\n",
+    "    - Generate a standalone HTML file with the needed resources."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# JavaScript"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Isn't this Sci**Py**."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "    SciJS?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Thoroughly unit tested."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Public API ready to be used:\n",
+    "\n",
+    "    http://emperor.microbio.me/uno/build/jsdoc/index.html"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# JavaScript"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "![JS-DOC](./images/js-doc.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# JavaScript"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "- Integration with SAGE2:\n",
+    "\n",
+    "    http://sage2.sagecommons.org/"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# JavaScript"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "- Integration with SAGE2:\n",
+    "\n",
+    "    http://sage2.sagecommons.org/\n",
+    "\n",
+    "![sage](./images/vroom.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# QIIME 2 integration"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- 1.5 hours to implement."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- In less than 80 lines of code we got a CLI, GUI and provenance tracking."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Consider QIIME 2 as a gateway to an expanded user base."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- CLI Provided through QIIME 2\n",
+    "\n",
+    "    https://github.com/qiime2/qiime2\n",
+    "    \n",
+    "    https://github.com/qiime2/q2-emperor/\n",
+    "\n",
+    "```bash\n",
+    "qiime emperor plot --help\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Outline\n",
+    "\n",
+    "- ~~Background (why $\\beta$-diversity).~~\n",
+    "\n",
+    "- ~~What is Emperor.~~\n",
+    "\n",
+    "- ~~How can we use Emperor.~~\n",
+    "    \n",
+    "- **Analyzing a use case.**"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Use case"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Let's leverage the technology we have available."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "- Create a small interface to:\n",
+    "\n",
+    "    - Subsample.\n",
+    "    - Compute a distance matrix.\n",
+    "        * Use all the cores in our machine.\n",
+    "    - Visualize.\n",
+    "    \n",
+    "    - This was kinda possible through E-vident https://github.com/biocore/evident"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "# biocore\n",
+    "from emperor.qiime_backports.parse import parse_mapping_file\n",
+    "from emperor import Emperor, nbinstall\n",
+    "\n",
+    "nbinstall()\n",
+    "\n",
+    "from skbio.stats.ordination import pcoa\n",
+    "from skbio.diversity import beta_diversity\n",
+    "from skbio import TreeNode\n",
+    "from skbio.io.util import open_file\n",
+    "\n",
+    "from biom import load_table\n",
+    "from biom.util import biom_open\n",
+    "\n",
+    "import qiime_default_reference\n",
+    "\n",
+    "# pydata/scipy\n",
+    "import pandas as pd\n",
+    "import numpy as np\n",
+    "\n",
+    "from scipy.spatial.distance import braycurtis, canberra\n",
+    "from ipywidgets import interact\n",
+    "from sklearn.metrics import pairwise_distances\n",
+    "from functools import partial"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "import warnings\n",
+    "# don't try this at home\n",
+    "warnings.filterwarnings(action='ignore', category=Warning)\n",
+    "\n",
+    "# -1 means all the processors available\n",
+    "pw_dists = partial(pairwise_distances, n_jobs=-1)\n",
+    "\n",
+    "def load_mf(fn):\n",
+    "    with open_file(fn) as f:\n",
+    "        mapping_data, header, _ = parse_mapping_file(f)\n",
+    "        _mapping_file = pd.DataFrame(mapping_data, columns=header)\n",
+    "        _mapping_file.set_index('SampleID', inplace=True)\n",
+    "    return _mapping_file"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Load the data (table and tree)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "mf = load_mf('keyboard/mapping-file.txt')\n",
+    "bt = load_table('keyboard/otu-table.biom')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "tree = TreeNode.read(qiime_default_reference.get_reference_tree())\n",
+    "\n",
+    "for n in tree.traverse():\n",
+    "    if n.length is None:\n",
+    "        n.length = 0"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Interaction function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def evident(n, metric):\n",
+    "    rarefied = bt.subsample(n)\n",
+    "    data = np.array([rarefied.data(i) for i in rarefied.ids()], dtype='int64')\n",
+    "    \n",
+    "    # phylogenetic\n",
+    "    if metric in ['unweighted_unifrac', 'weighted_unifrac']:\n",
+    "        res = pcoa(beta_diversity(metric, data, rarefied.ids(),\n",
+    "                                  otu_ids=rarefied.ids('observation'),\n",
+    "                                  tree=tree, pairwise_func=pw_dists))\n",
+    "    # non-phylogenetic\n",
+    "    else:\n",
+    "        res = pcoa(beta_diversity(metric, data, rarefied.ids(),\n",
+    "                                  pairwise_func=pw_dists))\n",
+    "    return Emperor(res, mf, remote=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "\n",
+       "if ($(\"#emperor-css\").length == 0){{\n",
+       "    $(\"head\").append([\n",
+       "\n",
+       "        '<link id=\"emperor-css\" rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/css/emperor.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery-ui.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/slick.grid.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/spectrum.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/chosen.min.css\">',\n",
+       "        '<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery.contextMenu.min.css\">'\n",
+       "    ]);\n",
+       "}}\n",
+       "</script>\n",
+       "\n",
+       "<div id='emperor-notebook-0xc38db72e' style=\"position: relative; width:100%; height:500px;\">\n",
+       "  <div class='loading' style=\"position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px\"><img src='https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files'></div>\n",
+       "</div>\n",
+       "</div>\n",
+       "\n",
+       "<script type=\"text/javascript\">\n",
+       "requirejs.config({\n",
+       "// the left side is the module name, and the right side is the path\n",
+       "// relative to the baseUrl attribute, do NOT include the .js extension\n",
+       "'paths': {\n",
+       "  /* jQuery */\n",
+       "  'jquery': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-2.1.4.min',\n",
+       "  'jqueryui': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-ui.min',\n",
+       "  'jquery_drag': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',\n",
+       "\n",
+       "  /* jQuery plugins */\n",
+       "  'chosen': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chosen.jquery.min',\n",
+       "  'spectrum': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/spectrum.min',\n",
+       "  'position': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.ui.position.min',\n",
+       "  'contextmenu': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.contextMenu.min',\n",
+       "\n",
+       "  /* other libraries */\n",
+       "  'underscore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/underscore-min',\n",
+       "  'chroma': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chroma.min',\n",
+       "  'filesaver': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/FileSaver.min',\n",
+       "  'blob': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/Blob',\n",
+       "  'd3': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/d3.min',\n",
+       "\n",
+       "\n",
+       "  /* THREE.js and plugins */\n",
+       "  'three': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.min',\n",
+       "  'orbitcontrols': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',\n",
+       "\n",
+       "  /* SlickGrid */\n",
+       "  'slickcore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.core.min',\n",
+       "  'slickgrid': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.grid.min',\n",
+       "  'slickformatters': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.editors.min',\n",
+       "  'slickeditors': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.formatters.min',\n",
+       "\n",
+       "  /* Emperor's objects */\n",
+       "  'util': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/util',\n",
+       "  'model': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/model',\n",
+       "  'view': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view',\n",
+       "  'controller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/controller',\n",
+       "  'draw': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/draw',\n",
+       "  'scene3d': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/sceneplotview3d',\n",
+       "  'viewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view-controller',\n",
+       "  'colorviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-view-controller',\n",
+       "  'visibilitycontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/visibility-controller',\n",
+       "  'scaleviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-view-controller',\n",
+       "  'shapecontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-controller',\n",
+       "  'axescontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/axes-controller',\n",
+       "  'shape-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-editor',\n",
+       "  'color-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-editor',\n",
+       "  'scale-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-editor',\n",
+       "  'shapes': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shapes'\n",
+       "},\n",
+       "/*\n",
+       "   Libraries that are not AMD compatible need shim to declare their\n",
+       "   dependencies.\n",
+       " */\n",
+       "'shim': {\n",
+       "  'jquery_drag': {\n",
+       "    'deps': ['jquery', 'jqueryui']\n",
+       "  },\n",
+       "  'chosen': {\n",
+       "    'deps': ['jquery'],\n",
+       "    'exports': 'jQuery.fn.chosen'\n",
+       "  },\n",
+       "  'contextmenu' : {\n",
+       "    'deps': ['jquery', 'jqueryui', 'position']\n",
+       "  },\n",
+       "  'filesaver' : {\n",
+       "    'deps': ['blob']\n",
+       "  },\n",
+       "  'orbitcontrols': {\n",
+       "    'deps': ['three']\n",
+       "  },\n",
+       "'slickcore': ['jqueryui'],\n",
+       "'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',\n",
+       "              'slickeditors']\n",
+       "}\n",
+       "});\n",
+       "\n",
+       "requirejs(\n",
+       "[\"jquery\", \"model\", \"controller\"],\n",
+       "function($, model, EmperorController) {\n",
+       "  var DecompositionModel = model.DecompositionModel;\n",
+       "\n",
+       "  var div = $('#emperor-notebook-0xc38db72e');\n",
+       "\n",
+       "  var ids = ['232.M9Thmr217', '232.M3Rinr217', '232.M2Enter217', '232.M3Midr217', '232.M3Tkey217', '232.M2Okey217', '232.M9Hkey217', '232.M9Pinl217', '232.M9Midl217', '232.M9Rinl217', '232.M2Midr217', '232.M2Lsft217', '232.M9Mkey217', '232.M3Wkey217', '232.M9Gkey217', '232.M3Midl217', '232.M3Pinl217', '232.M9Vkey217', '232.M2Tkey217', '232.M9Dkey217', '232.M2Gkey217', '232.M3Lkey217', '232.M9Pkey217', '232.M2Ykey217', '232.M2Ikey217', '232.M9Midr217', '232.M9Rinr217', '232.M2Lkey [...]
+       "  var coords = [[0.21082317684678245, -0.011729270321396059, 0.07648261103138583, -0.06472626907439936, 0.10107473617557027], [0.06452666285150635, 0.3501803743888372, -0.11259053525398556, -0.17401050281541014, -0.12731128224456892], [-0.36995186069497915, 0.07833256185821566, 0.1879046217929765, -0.12466637323629537, 0.25176710588622486], [0.15427944523121642, 0.22343487783597524, -0.05607151853394717, -0.011117198848393475, 0.11156772617293255], [0.2573240198016326, 0.01400794 [...]
+       "  var pct_var = [57.76677409980787, 7.908201592271172, 6.507455218533565, 3.6518880627434247, 2.960429398562099];\n",
+       "  var md_headers = ['SampleID', 'BarcodeSequence', 'LinkerPrimerSequence', 'center_name', 'center_project_name', 'emp_status', 'experiment_design_description', 'key_seq', 'library_construction_protocol', 'linker', 'platform', 'region', 'run_center', 'run_date', 'run_prefix', 'samp_size', 'sample_center', 'sequencing_meth', 'study_center', 'target_gene', 'target_subfragment', 'age', 'age_unit', 'altitude', 'anonymized_name', 'assigned_from_geo', 'body_habitat', 'body_product', 'bo [...]
+       "  var metadata = [['232.M9Thmr217', 'ACTACGTGTGGT', 'CATGCTGCCTCCCGTAGGAGT', 'CCME', 'Forensic_identification_using_skin_bacterial_communities', 'EMP', 'Forensic_identification_using_skin_bacterial_communities', 'TCAG', '16S_rRNA_gene_sequences_were_processed_according_to_the_methods_described_in_our_previous_publications_(Fierer_et_al.,_2008;_Hamady_et_al.,_2008)._Briefly,_sequences_<200_or_>300gnt_or_with_average_quality_scores_of_<25_were_removed_from_the_dataset,_as_were_thos [...]
+       "  var axesNames = ['PC1', 'PC2', 'PC3', 'PC4', 'PC5'];\n",
+       "\n",
+       "  var dm, ec;\n",
+       "\n",
+       "  function init() {\n",
+       "    // Initialize the DecompositionModel\n",
+       "    dm = new DecompositionModel(name, ids, coords, pct_var,\n",
+       "                                md_headers, metadata, axesNames);\n",
+       "    // Initialize the EmperorController\n",
+       "    ec = new EmperorController(dm, 'emperor-notebook-0xc38db72e');\n",
+       "  }\n",
+       "\n",
+       "  function animate() {\n",
+       "    requestAnimationFrame(animate);\n",
+       "    ec.render();\n",
+       "  }\n",
+       "  $(window).resize(function() {\n",
+       "    ec.resize(div.innerWidth(), div.innerHeight());\n",
+       "  });\n",
+       "\n",
+       "  $(function(){\n",
+       "    init();\n",
+       "    animate();\n",
+       "\n",
+       "  });\n",
+       "\n",
+       "}); // END REQUIRE.JS block\n",
+       "</script>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<emperor.core.Emperor at 0x118882278>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "interact(evident, n=(200, 2000, 50),\n",
+    "         metric=['unweighted_unifrac', 'weighted_unifrac', 'braycurtis', 'euclidean'],\n",
+    "         __manual=True)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div style='height:500px'></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Summarizing"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "Ready to be used!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "👍\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(b'\\xF0\\x9F\\x91\\x8D'.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "## version 1.0 $\\beta$ is out!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "```bash\n",
+    "pip install jupyter\n",
+    "pip install emperor --pre\n",
+    "\n",
+    "\n",
+    "conda install -c biocore emperor jupyter\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Acknowledments"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "-"
+    }
+   },
+   "source": [
+    "- Thanks to all our users (**cited 99 times since 2013**)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "from knightlab.members import current\n",
+    "from knightlab.members import past\n",
+    "from caporasolab.members import current as c_current\n",
+    "\n",
+    "__credits__ = ['Antonio Gonzalez', 'Joshua Shorenstein', 'Jamie Morton',\n",
+    "               'Jose Navas', 'Rob Knight'] + current + past + c_current"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {
+    "collapsed": false,
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'We are hiring, contact robknight at ucsd.edu'"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "one_more_thing()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "source": [
+    "<table style='border:none; width:100%;' cellspacing=\"0\" cellpadding=\"0\">\n",
+    "<tr style='border:none;'>\n",
+    "<td style='border:none;'>\n",
+    "<img src=\"https://upload.wikimedia.org/wikipedia/commons/f/f6/UCSD_logo.png\" alt=\"ucsd\" style=\"height: 50px;\"/>\n",
+    "</td>\n",
+    "<td style='border:none;'>\n",
+    "<img src=\"./images/knight-logo.png\" alt=\"knight-lab\" style=\"height: 100px;\"/>\n",
+    "</td>\n",
+    "</tr>\n",
+    "</table>"
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Slideshow",
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  },
+  "widgets": {
+   "state": {
+    "17677a6304674f019c1ee7d53f747793": {
+     "views": []
+    },
+    "2d01207ced7f414484f16f56e1ba830e": {
+     "views": []
+    },
+    "3538694b46744935ae560c76ceb8c1ed": {
+     "views": []
+    },
+    "6d68824a4ae94551844e3566bec2f449": {
+     "views": []
+    },
+    "ae42cd6d165947cd9085cca86055cedc": {
+     "views": []
+    },
+    "f47a2fe4ecb04d6892d275e10c00c878": {
+     "views": []
+    },
+    "f7d8683df9304a15bc6403d42363c1e0": {
+     "views": [
+      {
+       "cell_index": 83
+      }
+     ]
+    },
+    "fe964521953048ce80e0910bba898c47": {
+     "views": []
+    }
+   },
+   "version": "1.1.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/tips.csv b/examples/tips.csv
new file mode 100644
index 0000000..1280a10
--- /dev/null
+++ b/examples/tips.csv
@@ -0,0 +1,245 @@
+"total_bill","tip","sex","smoker","day","time","size"
+16.99,1.01,"Female","No","Sun","Dinner",2
+10.34,1.66,"Male","No","Sun","Dinner",3
+21.01,3.5,"Male","No","Sun","Dinner",3
+23.68,3.31,"Male","No","Sun","Dinner",2
+24.59,3.61,"Female","No","Sun","Dinner",4
+25.29,4.71,"Male","No","Sun","Dinner",4
+8.77,2,"Male","No","Sun","Dinner",2
+26.88,3.12,"Male","No","Sun","Dinner",4
+15.04,1.96,"Male","No","Sun","Dinner",2
+14.78,3.23,"Male","No","Sun","Dinner",2
+10.27,1.71,"Male","No","Sun","Dinner",2
+35.26,5,"Female","No","Sun","Dinner",4
+15.42,1.57,"Male","No","Sun","Dinner",2
+18.43,3,"Male","No","Sun","Dinner",4
+14.83,3.02,"Female","No","Sun","Dinner",2
+21.58,3.92,"Male","No","Sun","Dinner",2
+10.33,1.67,"Female","No","Sun","Dinner",3
+16.29,3.71,"Male","No","Sun","Dinner",3
+16.97,3.5,"Female","No","Sun","Dinner",3
+20.65,3.35,"Male","No","Sat","Dinner",3
+17.92,4.08,"Male","No","Sat","Dinner",2
+20.29,2.75,"Female","No","Sat","Dinner",2
+15.77,2.23,"Female","No","Sat","Dinner",2
+39.42,7.58,"Male","No","Sat","Dinner",4
+19.82,3.18,"Male","No","Sat","Dinner",2
+17.81,2.34,"Male","No","Sat","Dinner",4
+13.37,2,"Male","No","Sat","Dinner",2
+12.69,2,"Male","No","Sat","Dinner",2
+21.7,4.3,"Male","No","Sat","Dinner",2
+19.65,3,"Female","No","Sat","Dinner",2
+9.55,1.45,"Male","No","Sat","Dinner",2
+18.35,2.5,"Male","No","Sat","Dinner",4
+15.06,3,"Female","No","Sat","Dinner",2
+20.69,2.45,"Female","No","Sat","Dinner",4
+17.78,3.27,"Male","No","Sat","Dinner",2
+24.06,3.6,"Male","No","Sat","Dinner",3
+16.31,2,"Male","No","Sat","Dinner",3
+16.93,3.07,"Female","No","Sat","Dinner",3
+18.69,2.31,"Male","No","Sat","Dinner",3
+31.27,5,"Male","No","Sat","Dinner",3
+16.04,2.24,"Male","No","Sat","Dinner",3
+17.46,2.54,"Male","No","Sun","Dinner",2
+13.94,3.06,"Male","No","Sun","Dinner",2
+9.68,1.32,"Male","No","Sun","Dinner",2
+30.4,5.6,"Male","No","Sun","Dinner",4
+18.29,3,"Male","No","Sun","Dinner",2
+22.23,5,"Male","No","Sun","Dinner",2
+32.4,6,"Male","No","Sun","Dinner",4
+28.55,2.05,"Male","No","Sun","Dinner",3
+18.04,3,"Male","No","Sun","Dinner",2
+12.54,2.5,"Male","No","Sun","Dinner",2
+10.29,2.6,"Female","No","Sun","Dinner",2
+34.81,5.2,"Female","No","Sun","Dinner",4
+9.94,1.56,"Male","No","Sun","Dinner",2
+25.56,4.34,"Male","No","Sun","Dinner",4
+19.49,3.51,"Male","No","Sun","Dinner",2
+38.01,3,"Male","Yes","Sat","Dinner",4
+26.41,1.5,"Female","No","Sat","Dinner",2
+11.24,1.76,"Male","Yes","Sat","Dinner",2
+48.27,6.73,"Male","No","Sat","Dinner",4
+20.29,3.21,"Male","Yes","Sat","Dinner",2
+13.81,2,"Male","Yes","Sat","Dinner",2
+11.02,1.98,"Male","Yes","Sat","Dinner",2
+18.29,3.76,"Male","Yes","Sat","Dinner",4
+17.59,2.64,"Male","No","Sat","Dinner",3
+20.08,3.15,"Male","No","Sat","Dinner",3
+16.45,2.47,"Female","No","Sat","Dinner",2
+3.07,1,"Female","Yes","Sat","Dinner",1
+20.23,2.01,"Male","No","Sat","Dinner",2
+15.01,2.09,"Male","Yes","Sat","Dinner",2
+12.02,1.97,"Male","No","Sat","Dinner",2
+17.07,3,"Female","No","Sat","Dinner",3
+26.86,3.14,"Female","Yes","Sat","Dinner",2
+25.28,5,"Female","Yes","Sat","Dinner",2
+14.73,2.2,"Female","No","Sat","Dinner",2
+10.51,1.25,"Male","No","Sat","Dinner",2
+17.92,3.08,"Male","Yes","Sat","Dinner",2
+27.2,4,"Male","No","Thur","Lunch",4
+22.76,3,"Male","No","Thur","Lunch",2
+17.29,2.71,"Male","No","Thur","Lunch",2
+19.44,3,"Male","Yes","Thur","Lunch",2
+16.66,3.4,"Male","No","Thur","Lunch",2
+10.07,1.83,"Female","No","Thur","Lunch",1
+32.68,5,"Male","Yes","Thur","Lunch",2
+15.98,2.03,"Male","No","Thur","Lunch",2
+34.83,5.17,"Female","No","Thur","Lunch",4
+13.03,2,"Male","No","Thur","Lunch",2
+18.28,4,"Male","No","Thur","Lunch",2
+24.71,5.85,"Male","No","Thur","Lunch",2
+21.16,3,"Male","No","Thur","Lunch",2
+28.97,3,"Male","Yes","Fri","Dinner",2
+22.49,3.5,"Male","No","Fri","Dinner",2
+5.75,1,"Female","Yes","Fri","Dinner",2
+16.32,4.3,"Female","Yes","Fri","Dinner",2
+22.75,3.25,"Female","No","Fri","Dinner",2
+40.17,4.73,"Male","Yes","Fri","Dinner",4
+27.28,4,"Male","Yes","Fri","Dinner",2
+12.03,1.5,"Male","Yes","Fri","Dinner",2
+21.01,3,"Male","Yes","Fri","Dinner",2
+12.46,1.5,"Male","No","Fri","Dinner",2
+11.35,2.5,"Female","Yes","Fri","Dinner",2
+15.38,3,"Female","Yes","Fri","Dinner",2
+44.3,2.5,"Female","Yes","Sat","Dinner",3
+22.42,3.48,"Female","Yes","Sat","Dinner",2
+20.92,4.08,"Female","No","Sat","Dinner",2
+15.36,1.64,"Male","Yes","Sat","Dinner",2
+20.49,4.06,"Male","Yes","Sat","Dinner",2
+25.21,4.29,"Male","Yes","Sat","Dinner",2
+18.24,3.76,"Male","No","Sat","Dinner",2
+14.31,4,"Female","Yes","Sat","Dinner",2
+14,3,"Male","No","Sat","Dinner",2
+7.25,1,"Female","No","Sat","Dinner",1
+38.07,4,"Male","No","Sun","Dinner",3
+23.95,2.55,"Male","No","Sun","Dinner",2
+25.71,4,"Female","No","Sun","Dinner",3
+17.31,3.5,"Female","No","Sun","Dinner",2
+29.93,5.07,"Male","No","Sun","Dinner",4
+10.65,1.5,"Female","No","Thur","Lunch",2
+12.43,1.8,"Female","No","Thur","Lunch",2
+24.08,2.92,"Female","No","Thur","Lunch",4
+11.69,2.31,"Male","No","Thur","Lunch",2
+13.42,1.68,"Female","No","Thur","Lunch",2
+14.26,2.5,"Male","No","Thur","Lunch",2
+15.95,2,"Male","No","Thur","Lunch",2
+12.48,2.52,"Female","No","Thur","Lunch",2
+29.8,4.2,"Female","No","Thur","Lunch",6
+8.52,1.48,"Male","No","Thur","Lunch",2
+14.52,2,"Female","No","Thur","Lunch",2
+11.38,2,"Female","No","Thur","Lunch",2
+22.82,2.18,"Male","No","Thur","Lunch",3
+19.08,1.5,"Male","No","Thur","Lunch",2
+20.27,2.83,"Female","No","Thur","Lunch",2
+11.17,1.5,"Female","No","Thur","Lunch",2
+12.26,2,"Female","No","Thur","Lunch",2
+18.26,3.25,"Female","No","Thur","Lunch",2
+8.51,1.25,"Female","No","Thur","Lunch",2
+10.33,2,"Female","No","Thur","Lunch",2
+14.15,2,"Female","No","Thur","Lunch",2
+16,2,"Male","Yes","Thur","Lunch",2
+13.16,2.75,"Female","No","Thur","Lunch",2
+17.47,3.5,"Female","No","Thur","Lunch",2
+34.3,6.7,"Male","No","Thur","Lunch",6
+41.19,5,"Male","No","Thur","Lunch",5
+27.05,5,"Female","No","Thur","Lunch",6
+16.43,2.3,"Female","No","Thur","Lunch",2
+8.35,1.5,"Female","No","Thur","Lunch",2
+18.64,1.36,"Female","No","Thur","Lunch",3
+11.87,1.63,"Female","No","Thur","Lunch",2
+9.78,1.73,"Male","No","Thur","Lunch",2
+7.51,2,"Male","No","Thur","Lunch",2
+14.07,2.5,"Male","No","Sun","Dinner",2
+13.13,2,"Male","No","Sun","Dinner",2
+17.26,2.74,"Male","No","Sun","Dinner",3
+24.55,2,"Male","No","Sun","Dinner",4
+19.77,2,"Male","No","Sun","Dinner",4
+29.85,5.14,"Female","No","Sun","Dinner",5
+48.17,5,"Male","No","Sun","Dinner",6
+25,3.75,"Female","No","Sun","Dinner",4
+13.39,2.61,"Female","No","Sun","Dinner",2
+16.49,2,"Male","No","Sun","Dinner",4
+21.5,3.5,"Male","No","Sun","Dinner",4
+12.66,2.5,"Male","No","Sun","Dinner",2
+16.21,2,"Female","No","Sun","Dinner",3
+13.81,2,"Male","No","Sun","Dinner",2
+17.51,3,"Female","Yes","Sun","Dinner",2
+24.52,3.48,"Male","No","Sun","Dinner",3
+20.76,2.24,"Male","No","Sun","Dinner",2
+31.71,4.5,"Male","No","Sun","Dinner",4
+10.59,1.61,"Female","Yes","Sat","Dinner",2
+10.63,2,"Female","Yes","Sat","Dinner",2
+50.81,10,"Male","Yes","Sat","Dinner",3
+15.81,3.16,"Male","Yes","Sat","Dinner",2
+7.25,5.15,"Male","Yes","Sun","Dinner",2
+31.85,3.18,"Male","Yes","Sun","Dinner",2
+16.82,4,"Male","Yes","Sun","Dinner",2
+32.9,3.11,"Male","Yes","Sun","Dinner",2
+17.89,2,"Male","Yes","Sun","Dinner",2
+14.48,2,"Male","Yes","Sun","Dinner",2
+9.6,4,"Female","Yes","Sun","Dinner",2
+34.63,3.55,"Male","Yes","Sun","Dinner",2
+34.65,3.68,"Male","Yes","Sun","Dinner",4
+23.33,5.65,"Male","Yes","Sun","Dinner",2
+45.35,3.5,"Male","Yes","Sun","Dinner",3
+23.17,6.5,"Male","Yes","Sun","Dinner",4
+40.55,3,"Male","Yes","Sun","Dinner",2
+20.69,5,"Male","No","Sun","Dinner",5
+20.9,3.5,"Female","Yes","Sun","Dinner",3
+30.46,2,"Male","Yes","Sun","Dinner",5
+18.15,3.5,"Female","Yes","Sun","Dinner",3
+23.1,4,"Male","Yes","Sun","Dinner",3
+15.69,1.5,"Male","Yes","Sun","Dinner",2
+19.81,4.19,"Female","Yes","Thur","Lunch",2
+28.44,2.56,"Male","Yes","Thur","Lunch",2
+15.48,2.02,"Male","Yes","Thur","Lunch",2
+16.58,4,"Male","Yes","Thur","Lunch",2
+7.56,1.44,"Male","No","Thur","Lunch",2
+10.34,2,"Male","Yes","Thur","Lunch",2
+43.11,5,"Female","Yes","Thur","Lunch",4
+13,2,"Female","Yes","Thur","Lunch",2
+13.51,2,"Male","Yes","Thur","Lunch",2
+18.71,4,"Male","Yes","Thur","Lunch",3
+12.74,2.01,"Female","Yes","Thur","Lunch",2
+13,2,"Female","Yes","Thur","Lunch",2
+16.4,2.5,"Female","Yes","Thur","Lunch",2
+20.53,4,"Male","Yes","Thur","Lunch",4
+16.47,3.23,"Female","Yes","Thur","Lunch",3
+26.59,3.41,"Male","Yes","Sat","Dinner",3
+38.73,3,"Male","Yes","Sat","Dinner",4
+24.27,2.03,"Male","Yes","Sat","Dinner",2
+12.76,2.23,"Female","Yes","Sat","Dinner",2
+30.06,2,"Male","Yes","Sat","Dinner",3
+25.89,5.16,"Male","Yes","Sat","Dinner",4
+48.33,9,"Male","No","Sat","Dinner",4
+13.27,2.5,"Female","Yes","Sat","Dinner",2
+28.17,6.5,"Female","Yes","Sat","Dinner",3
+12.9,1.1,"Female","Yes","Sat","Dinner",2
+28.15,3,"Male","Yes","Sat","Dinner",5
+11.59,1.5,"Male","Yes","Sat","Dinner",2
+7.74,1.44,"Male","Yes","Sat","Dinner",2
+30.14,3.09,"Female","Yes","Sat","Dinner",4
+12.16,2.2,"Male","Yes","Fri","Lunch",2
+13.42,3.48,"Female","Yes","Fri","Lunch",2
+8.58,1.92,"Male","Yes","Fri","Lunch",1
+15.98,3,"Female","No","Fri","Lunch",3
+13.42,1.58,"Male","Yes","Fri","Lunch",2
+16.27,2.5,"Female","Yes","Fri","Lunch",2
+10.09,2,"Female","Yes","Fri","Lunch",2
+20.45,3,"Male","No","Sat","Dinner",4
+13.28,2.72,"Male","No","Sat","Dinner",2
+22.12,2.88,"Female","Yes","Sat","Dinner",2
+24.01,2,"Male","Yes","Sat","Dinner",4
+15.69,3,"Male","Yes","Sat","Dinner",3
+11.61,3.39,"Male","No","Sat","Dinner",2
+10.77,1.47,"Male","No","Sat","Dinner",2
+15.53,3,"Male","Yes","Sat","Dinner",2
+10.07,1.25,"Male","No","Sat","Dinner",2
+12.6,1,"Male","Yes","Sat","Dinner",2
+32.83,1.17,"Male","Yes","Sat","Dinner",2
+35.83,4.67,"Female","No","Sat","Dinner",3
+29.03,5.92,"Male","No","Sat","Dinner",3
+27.18,2,"Female","Yes","Sat","Dinner",2
+22.67,2,"Male","Yes","Sat","Dinner",2
+17.82,1.75,"Male","No","Sat","Dinner",2
+18.78,3,"Female","No","Thur","Dinner",2
diff --git a/licenses/nb-slideshow-template.txt b/licenses/nb-slideshow-template.txt
new file mode 100644
index 0000000..24d72d2
--- /dev/null
+++ b/licenses/nb-slideshow-template.txt
@@ -0,0 +1,30 @@
+Licensed under the terms of the Simplified BSD license:
+http://opensource.org/licenses/BSD-3-Clause
+
+
+Copyright (c) 2013, Fernando Perez.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+Neither the name of the <ORGANIZATION> nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/licenses/numpydoc.txt b/licenses/numpydoc.txt
new file mode 100644
index 0000000..fe10d70
--- /dev/null
+++ b/licenses/numpydoc.txt
@@ -0,0 +1 @@
+numpydoc license is at scikit-bio/doc/sphinxext/numpydoc/LICENSE.txt
diff --git a/licenses/scikit-learn.txt b/licenses/scikit-learn.txt
new file mode 100644
index 0000000..28a97b9
--- /dev/null
+++ b/licenses/scikit-learn.txt
@@ -0,0 +1,35 @@
+------------------------------------------------------------------------------
+    The file doc/source/.static/copybutton.js has the following license:
+
+New BSD License
+
+Copyright (c) 2007–2014 The scikit-learn developers.
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  a. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+  b. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  c. Neither the name of the Scikit-learn Developers  nor the names of
+     its contributors may be used to endorse or promote products
+     derived from this software without specific prior written
+     permission. 
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
diff --git a/licenses/scipy.txt b/licenses/scipy.txt
new file mode 100644
index 0000000..b72893b
--- /dev/null
+++ b/licenses/scipy.txt
@@ -0,0 +1,31 @@
+Copyright (c) 2001, 2002 Enthought, Inc.
+All rights reserved.
+
+Copyright (c) 2003-2012 SciPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  a. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+  b. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  c. Neither the name of Enthought nor the names of the SciPy Developers
+     may be used to endorse or promote products derived from this software
+     without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/emperor/support_files/js/js/ctm/license/js-lzma.txt b/licenses/sphinx-bootstrap-theme.txt
similarity index 96%
rename from emperor/support_files/js/js/ctm/license/js-lzma.txt
rename to licenses/sphinx-bootstrap-theme.txt
index 8abd005..a22b4af 100644
--- a/emperor/support_files/js/js/ctm/license/js-lzma.txt
+++ b/licenses/sphinx-bootstrap-theme.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2011 Juan Mellado
+Copyright (c) 2011-2014 Ryan Roemer
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/licenses/ssw.txt b/licenses/ssw.txt
new file mode 100644
index 0000000..39f340f
--- /dev/null
+++ b/licenses/ssw.txt
@@ -0,0 +1,46 @@
+/* The MIT License
+
+   Copyright (c) 2012-1015 Boston College.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+/* Contact: Mengyao Zhao <zhangmp at bc.edu> */
+
+/*
+ *  ssw.c
+ *
+ *  Created by Mengyao Zhao on 6/22/10.
+ *  Copyright 2010 Boston College. All rights reserved.
+ *  Version 0.1.4
+ *  Last revision by Mengyao Zhao on 12/07/12.
+ *
+ */
+
+/*
+ *  ssw.h
+ *
+ *  Created by Mengyao Zhao on 6/22/10.
+ *  Copyright 2010 Boston College. All rights reserved.
+ *  Version 0.1.4
+ *  Last revision by Mengyao Zhao on 01/30/13.
+ *
+ */
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..08dd91d
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,7 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
diff --git a/tests/_test_core_strings.py b/tests/_test_core_strings.py
new file mode 100644
index 0000000..63b0851
--- /dev/null
+++ b/tests/_test_core_strings.py
@@ -0,0 +1,544 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+# flake8: noqa
+"""
+These are intended to be HTML formatted strings that are used throughout the
+codebase and not included in for example format.py, because the length would
+violate PEP-8 rules.
+"""
+
+PCOA_STRING = u"""Eigvals	9
+0.479412119045	0.29201495623	0.247449246064	0.201496072404	0.180076127632\
+	0.147806772727	0.135795927213	0.112259695609	0.0
+
+Proportion explained	9
+0.266887048633	0.162563704022	0.137754129161	0.11217215823	0.10024774995\
+	0.0822835130237	0.0755971173665	0.0624945796136	0.0
+
+Species	0	0
+
+Site	9	9
+PC.636	-0.276542163845	-0.144964375408	0.0666467344429	-0.0677109454288\
+	0.176070269506	0.072969390136	-0.229889463523	-0.0465989416581\
+	-0.0
+PC.635	-0.237661393984	0.0460527772512	-0.138135814766	0.159061025229\
+	-0.247484698646	-0.115211468101	-0.112864033263	0.0647940729676\
+	-0.0
+PC.356	0.228820399536	-0.130142097093	-0.287149447883	0.0864498846421\
+	0.0442951919304	0.20604260722	0.0310003571386	0.0719920436501	-0.0
+PC.481	0.0422628480532	-0.0139681511889	0.0635314615517	-0.346120552134\
+	-0.127813807608	0.0139350721063	0.0300206887328	0.140147849223	-0.0
+PC.354	0.280399117569	-0.0060128286014	0.0234854344148	-0.0468109474823\
+	-0.146624450094	0.00566979124596	-0.0354299634191\
+	-0.255785794275	-0.0
+PC.593	0.232872767451	0.139788385269	0.322871079774	0.18334700682\
+	0.0204661596818	0.0540589147147	-0.0366250872041	0.0998235721267\
+	-0.0
+PC.355	0.170517581885	-0.194113268955	-0.0308965283066	0.0198086158783\
+	0.155100062794	-0.279923941712	0.0576092515759	0.0242481862127	-0.0
+PC.607	-0.0913299284215	0.424147148265	-0.135627421345	-0.057519480907\
+	0.151363490722	-0.0253935675552	0.0517306152066	-0.038738217609\
+	-0.0
+PC.634	-0.349339228244	-0.120787589539	0.115274502117	0.0694953933826\
+	-0.0253722182853	0.067853201946	0.244447634756	-0.0598827706386\
+	-0.0
+
+Biplot	0	0
+
+Site constraints	0	0
+"""
+
+HTML_STRING = u"""
+<script type="text/javascript">
+
+if ($("#emperor-css").length == 0){{
+    $("head").append([
+
+        '<link id="emperor-css" rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/css/emperor.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery-ui.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/slick.grid.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/spectrum.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/chosen.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery.contextMenu.min.css">'
+    ]);
+}}
+</script>
+
+<div id='emperor-notebook-0x9cb72f54' style="position: relative; width:100%; height:500px;">
+  <div class='loading' style="position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px"><img src='https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files'></div>
+</div>
+</div>
+
+<script type="text/javascript">
+requirejs.config({
+// the left side is the module name, and the right side is the path
+// relative to the baseUrl attribute, do NOT include the .js extension
+'paths': {
+  /* jQuery */
+  'jquery': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-2.1.4.min',
+  'jqueryui': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-ui.min',
+  'jquery_drag': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',
+
+  /* jQuery plugins */
+  'chosen': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chosen.jquery.min',
+  'spectrum': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/spectrum.min',
+  'position': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.ui.position.min',
+  'contextmenu': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.contextMenu.min',
+
+  /* other libraries */
+  'underscore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/underscore-min',
+  'chroma': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chroma.min',
+  'filesaver': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/FileSaver.min',
+  'blob': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/Blob',
+  'd3': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/d3.min',
+
+  /* THREE.js and plugins */
+  'three': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.min',
+  'orbitcontrols': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',
+  'projector': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/Projector',
+  'svgrenderer': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/SVGRenderer',
+
+  /* SlickGrid */
+  'slickcore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.core.min',
+  'slickgrid': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.grid.min',
+  'slickformatters': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.editors.min',
+  'slickeditors': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.formatters.min',
+
+  /* Emperor's objects */
+  'util': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/util',
+  'model': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/model',
+  'view': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view',
+  'controller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/controller',
+  'draw': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/draw',
+  'scene3d': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/sceneplotview3d',
+  'abcviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/abc-view-controller',
+  'viewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view-controller',
+  'colorviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-view-controller',
+  'visibilitycontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/visibility-controller',
+  'scaleviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-view-controller',
+  'shapecontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-controller',
+  'axescontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/axes-controller',
+  'shape-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-editor',
+  'color-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-editor',
+  'scale-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-editor',
+  'shapes': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shapes'
+},
+/*
+   Libraries that are not AMD compatible need shim to declare their
+   dependencies.
+ */
+'shim': {
+  'jquery_drag': {
+    'deps': ['jquery', 'jqueryui']
+  },
+  'chosen': {
+    'deps': ['jquery'],
+    'exports': 'jQuery.fn.chosen'
+  },
+  'contextmenu' : {
+    'deps': ['jquery', 'jqueryui', 'position']
+  },
+  'filesaver' : {
+    'deps': ['blob']
+  },
+  'orbitcontrols': {
+    'deps': ['three']
+  },
+  'projector': {
+    'deps': ['three']
+  },
+  'svgrenderer': {
+    'deps': ['orbitcontrols', 'projector']
+  },
+'slickcore': ['jqueryui'],
+'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
+              'slickeditors']
+}
+});
+
+requirejs(
+["jquery", "model", "controller"],
+function($, model, EmperorController) {
+  var DecompositionModel = model.DecompositionModel;
+
+  var div = $('#emperor-notebook-0x9cb72f54');
+
+  var ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593', 'PC.355', 'PC.607', 'PC.634'];
+  var coords = [[-0.276542163845, -0.144964375408, 0.0666467344429, -0.0677109454288, 0.176070269506], [-0.237661393984, 0.0460527772512, -0.138135814766, 0.159061025229, -0.247484698646], [0.228820399536, -0.130142097093, -0.287149447883, 0.0864498846421, 0.0442951919304], [0.0422628480532, -0.0139681511889, 0.0635314615517, -0.346120552134, -0.127813807608], [0.280399117569, -0.0060128286014, 0.0234854344148, -0.0468109474823, -0.146624450094], [0.232872767451, 0.139788385269, 0.322871 [...]
+  var pct_var = [26.6887048633, 16.256370402199998, 13.775412916099999, 11.217215823, 10.024774995000001];
+  var md_headers = ['SampleID', 'Treatment', 'DOB', 'Description'];
+  var metadata = [['PC.636', 'Fast', '20080116', 'Fasting_mouse_I.D._636'], ['PC.635', 'Fast', '20080116', 'Fasting_mouse_I.D._635'], ['PC.356', 'Control', '20061126', 'Control_mouse_I.D._356'], ['PC.481', 'Control', '20070314', 'Control_mouse_I.D._481'], ['PC.354', 'Control', '20061218', 'Ctrol_mouse_I.D._354'], ['PC.593', 'Control', '20071210', 'Control_mouse_I.D._593'], ['PC.355', 'Control', '20061218', 'Control_mouse_I.D._355'], ['PC.607', 'Fast', '20071112', 'Fasting_mouse_I.D._607' [...]
+  var axesNames = [0, 1, 2, 3, 4];
+
+  var dm, ec;
+
+  function init() {
+    // Initialize the DecompositionModel
+    dm = new DecompositionModel(name, ids, coords, pct_var,
+                                md_headers, metadata, axesNames);
+    // Initialize the EmperorController
+    ec = new EmperorController(dm, 'emperor-notebook-0x9cb72f54');
+  }
+
+  function animate() {
+    requestAnimationFrame(animate);
+    ec.render();
+  }
+  $(window).resize(function() {
+    ec.resize(div.innerWidth(), div.innerHeight());
+  });
+
+  $(function(){
+    init();
+    animate();
+
+  });
+
+}); // END REQUIRE.JS block
+</script>"""
+
+STANDALONE_HTML_STRING = """<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title>Emperor</title>
+    <!-- core dependencies that are otherwise included via the jupyter notebook -->
+    <script src="./some-local-path//vendor/js/require-2.1.22.min.js"></script>
+    <script src="./some-local-path//vendor/js/jquery-2.1.4.min.js"></script>
+    <meta charset="utf-8">
+
+    <script type="text/javascript">
+
+if ($("#emperor-css").length == 0){{
+    $("head").append([
+
+        '<link id="emperor-css" rel="stylesheet" type="text/css" href="./some-local-path//css/emperor.css">',
+        '<link rel="stylesheet" type="text/css" href="./some-local-path//vendor/css/jquery-ui.min.css">',
+        '<link rel="stylesheet" type="text/css" href="./some-local-path//vendor/css/slick.grid.min.css">',
+        '<link rel="stylesheet" type="text/css" href="./some-local-path//vendor/css/spectrum.min.css">',
+        '<link rel="stylesheet" type="text/css" href="./some-local-path//vendor/css/chosen.min.css">',
+        '<link rel="stylesheet" type="text/css" href="./some-local-path//vendor/css/jquery.contextMenu.min.css">'
+    ]);
+}}
+</script>
+
+
+    <style>
+      #emperor-notebook-0x9cb72f54 {
+        height:100vh !important;
+        padding: 0px !important;
+      }
+      body {
+        margin: 0;
+        padding: 0;
+        border: 0;
+        outline: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <div id='emperor-notebook-0x9cb72f54' style="position: relative; width:100%; height:500px;">
+  <div class='loading' style="position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px"><img src='./some-local-path//img/emperor.png' alt='Emperor resources missing. Expected them to be found in ./some-local-path/'></div>
+</div>
+</div>
+
+<script type="text/javascript">
+requirejs.config({
+// the left side is the module name, and the right side is the path
+// relative to the baseUrl attribute, do NOT include the .js extension
+'paths': {
+  /* jQuery */
+  'jquery': './some-local-path//vendor/js/jquery-2.1.4.min',
+  'jqueryui': './some-local-path//vendor/js/jquery-ui.min',
+  'jquery_drag': './some-local-path//vendor/js/jquery.event.drag-2.2.min',
+
+  /* jQuery plugins */
+  'chosen': './some-local-path//vendor/js/chosen.jquery.min',
+  'spectrum': './some-local-path//vendor/js/spectrum.min',
+  'position': './some-local-path//vendor/js/jquery.ui.position.min',
+  'contextmenu': './some-local-path//vendor/js/jquery.contextMenu.min',
+
+  /* other libraries */
+  'underscore': './some-local-path//vendor/js/underscore-min',
+  'chroma': './some-local-path//vendor/js/chroma.min',
+  'filesaver': './some-local-path//vendor/js/FileSaver.min',
+  'blob': './some-local-path//vendor/js/Blob',
+  'd3': './some-local-path//vendor/js/d3.min',
+
+  /* THREE.js and plugins */
+  'three': './some-local-path//vendor/js/three.min',
+  'orbitcontrols': './some-local-path//vendor/js/three.js-plugins/OrbitControls',
+  'projector': './some-local-path//vendor/js/three.js-plugins/Projector',
+  'svgrenderer': './some-local-path//vendor/js/three.js-plugins/SVGRenderer',
+
+  /* SlickGrid */
+  'slickcore': './some-local-path//vendor/js/slick.core.min',
+  'slickgrid': './some-local-path//vendor/js/slick.grid.min',
+  'slickformatters': './some-local-path//vendor/js/slick.editors.min',
+  'slickeditors': './some-local-path//vendor/js/slick.formatters.min',
+
+  /* Emperor's objects */
+  'util': './some-local-path//js/util',
+  'model': './some-local-path//js/model',
+  'view': './some-local-path//js/view',
+  'controller': './some-local-path//js/controller',
+  'draw': './some-local-path//js/draw',
+  'scene3d': './some-local-path//js/sceneplotview3d',
+  'abcviewcontroller': './some-local-path//js/abc-view-controller',
+  'viewcontroller': './some-local-path//js/view-controller',
+  'colorviewcontroller': './some-local-path//js/color-view-controller',
+  'visibilitycontroller': './some-local-path//js/visibility-controller',
+  'scaleviewcontroller': './some-local-path//js/scale-view-controller',
+  'shapecontroller': './some-local-path//js/shape-controller',
+  'axescontroller': './some-local-path//js/axes-controller',
+  'shape-editor': './some-local-path//js/shape-editor',
+  'color-editor': './some-local-path//js/color-editor',
+  'scale-editor': './some-local-path//js/scale-editor',
+  'shapes': './some-local-path//js/shapes'
+},
+/*
+   Libraries that are not AMD compatible need shim to declare their
+   dependencies.
+ */
+'shim': {
+  'jquery_drag': {
+    'deps': ['jquery', 'jqueryui']
+  },
+  'chosen': {
+    'deps': ['jquery'],
+    'exports': 'jQuery.fn.chosen'
+  },
+  'contextmenu' : {
+    'deps': ['jquery', 'jqueryui', 'position']
+  },
+  'filesaver' : {
+    'deps': ['blob']
+  },
+  'orbitcontrols': {
+    'deps': ['three']
+  },
+  'projector': {
+    'deps': ['three']
+  },
+  'svgrenderer': {
+    'deps': ['orbitcontrols', 'projector']
+  },
+'slickcore': ['jqueryui'],
+'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
+              'slickeditors']
+}
+});
+
+requirejs(
+["jquery", "model", "controller"],
+function($, model, EmperorController) {
+  var DecompositionModel = model.DecompositionModel;
+
+  var div = $('#emperor-notebook-0x9cb72f54');
+
+  var ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593', 'PC.355', 'PC.607', 'PC.634'];
+  var coords = [[-0.276542163845, -0.144964375408, 0.0666467344429, -0.0677109454288, 0.176070269506], [-0.237661393984, 0.0460527772512, -0.138135814766, 0.159061025229, -0.247484698646], [0.228820399536, -0.130142097093, -0.287149447883, 0.0864498846421, 0.0442951919304], [0.0422628480532, -0.0139681511889, 0.0635314615517, -0.346120552134, -0.127813807608], [0.280399117569, -0.0060128286014, 0.0234854344148, -0.0468109474823, -0.146624450094], [0.232872767451, 0.139788385269, 0.322871 [...]
+  var pct_var = [26.6887048633, 16.256370402199998, 13.775412916099999, 11.217215823, 10.024774995000001];
+  var md_headers = ['SampleID', 'Treatment', 'DOB', 'Description'];
+  var metadata = [['PC.636', 'Fast', '20080116', 'Fasting_mouse_I.D._636'], ['PC.635', 'Fast', '20080116', 'Fasting_mouse_I.D._635'], ['PC.356', 'Control', '20061126', 'Control_mouse_I.D._356'], ['PC.481', 'Control', '20070314', 'Control_mouse_I.D._481'], ['PC.354', 'Control', '20061218', 'Ctrol_mouse_I.D._354'], ['PC.593', 'Control', '20071210', 'Control_mouse_I.D._593'], ['PC.355', 'Control', '20061218', 'Control_mouse_I.D._355'], ['PC.607', 'Fast', '20071112', 'Fasting_mouse_I.D._607' [...]
+  var axesNames = [0, 1, 2, 3, 4];
+
+  var dm, ec;
+
+  function init() {
+    // Initialize the DecompositionModel
+    dm = new DecompositionModel(name, ids, coords, pct_var,
+                                md_headers, metadata, axesNames);
+    // Initialize the EmperorController
+    ec = new EmperorController(dm, 'emperor-notebook-0x9cb72f54');
+  }
+
+  function animate() {
+    requestAnimationFrame(animate);
+    ec.render();
+  }
+  $(window).resize(function() {
+    ec.resize(div.innerWidth(), div.innerHeight());
+  });
+
+  $(function(){
+    init();
+    animate();
+
+  });
+
+}); // END REQUIRE.JS block
+</script>
+  </body>
+</html>"""
+
+HTML_STRING_CUSTOM_AXES = u"""
+<script type="text/javascript">
+
+if ($("#emperor-css").length == 0){{
+    $("head").append([
+
+        '<link id="emperor-css" rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/css/emperor.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery-ui.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/slick.grid.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/spectrum.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/chosen.min.css">',
+        '<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/css/jquery.contextMenu.min.css">'
+    ]);
+}}
+</script>
+
+<div id='emperor-notebook-0x9cb72f54' style="position: relative; width:100%; height:500px;">
+  <div class='loading' style="position: absolute;top: 50%;left: 50%;margin-left: -229px; margin-top: -59px; z-index: 10000;height:118px;width:458px;padding:0px"><img src='https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/img/emperor.png' alt='Emperor resources missing. Expected them to be found in https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files'></div>
+</div>
+</div>
+
+<script type="text/javascript">
+requirejs.config({
+// the left side is the module name, and the right side is the path
+// relative to the baseUrl attribute, do NOT include the .js extension
+'paths': {
+  /* jQuery */
+  'jquery': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-2.1.4.min',
+  'jqueryui': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery-ui.min',
+  'jquery_drag': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.event.drag-2.2.min',
+
+  /* jQuery plugins */
+  'chosen': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chosen.jquery.min',
+  'spectrum': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/spectrum.min',
+  'position': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.ui.position.min',
+  'contextmenu': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/jquery.contextMenu.min',
+
+  /* other libraries */
+  'underscore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/underscore-min',
+  'chroma': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/chroma.min',
+  'filesaver': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/FileSaver.min',
+  'blob': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/Blob',
+  'd3': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/d3.min',
+
+  /* THREE.js and plugins */
+  'three': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.min',
+  'orbitcontrols': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/OrbitControls',
+  'projector': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/Projector',
+  'svgrenderer': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/three.js-plugins/SVGRenderer',
+
+  /* SlickGrid */
+  'slickcore': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.core.min',
+  'slickgrid': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.grid.min',
+  'slickformatters': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.editors.min',
+  'slickeditors': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/vendor/js/slick.formatters.min',
+
+  /* Emperor's objects */
+  'util': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/util',
+  'model': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/model',
+  'view': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view',
+  'controller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/controller',
+  'draw': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/draw',
+  'scene3d': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/sceneplotview3d',
+  'abcviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/abc-view-controller',
+  'viewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/view-controller',
+  'colorviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-view-controller',
+  'visibilitycontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/visibility-controller',
+  'scaleviewcontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-view-controller',
+  'shapecontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-controller',
+  'axescontroller': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/axes-controller',
+  'shape-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shape-editor',
+  'color-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/color-editor',
+  'scale-editor': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/scale-editor',
+  'shapes': 'https://cdn.rawgit.com/biocore/emperor/new-api/emperor/support_files/js/shapes'
+},
+/*
+   Libraries that are not AMD compatible need shim to declare their
+   dependencies.
+ */
+'shim': {
+  'jquery_drag': {
+    'deps': ['jquery', 'jqueryui']
+  },
+  'chosen': {
+    'deps': ['jquery'],
+    'exports': 'jQuery.fn.chosen'
+  },
+  'contextmenu' : {
+    'deps': ['jquery', 'jqueryui', 'position']
+  },
+  'filesaver' : {
+    'deps': ['blob']
+  },
+  'orbitcontrols': {
+    'deps': ['three']
+  },
+  'projector': {
+    'deps': ['three']
+  },
+  'svgrenderer': {
+    'deps': ['orbitcontrols', 'projector']
+  },
+'slickcore': ['jqueryui'],
+'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
+              'slickeditors']
+}
+});
+
+requirejs(
+["jquery", "model", "controller"],
+function($, model, EmperorController) {
+  var DecompositionModel = model.DecompositionModel;
+
+  var div = $('#emperor-notebook-0x9cb72f54');
+
+  var ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593', 'PC.355', 'PC.607', 'PC.634'];
+  var coords = [[0.560798235138, -0.276542163845, -0.144964375408, 0.0666467344429, -0.0677109454288, 0.176070269506], [0.560798235138, -0.237661393984, 0.0460527772512, -0.138135814766, 0.159061025229, -0.247484698646], [-0.349339228244, 0.228820399536, -0.130142097093, -0.287149447883, 0.0864498846421, 0.0442951919304], [0.09101585409164065, 0.0422628480532, -0.0139681511889, 0.0635314615517, -0.346120552134, -0.127813807608], [-0.3449299261570519, 0.280399117569, -0.0060128286014, 0.0 [...]
+  var pct_var = [-1.0, 26.6887048633, 16.256370402199998, 13.775412916099999, 11.217215823, 10.024774995000001];
+  var md_headers = ['SampleID', 'Treatment', 'DOB', 'Description'];
+  var metadata = [['PC.636', 'Fast', '20080116', 'Fasting_mouse_I.D._636'], ['PC.635', 'Fast', '20080116', 'Fasting_mouse_I.D._635'], ['PC.356', 'Control', '20061126', 'Control_mouse_I.D._356'], ['PC.481', 'Control', '20070314', 'Control_mouse_I.D._481'], ['PC.354', 'Control', '20061218', 'Ctrol_mouse_I.D._354'], ['PC.593', 'Control', '20071210', 'Control_mouse_I.D._593'], ['PC.355', 'Control', '20061218', 'Control_mouse_I.D._355'], ['PC.607', 'Fast', '20071112', 'Fasting_mouse_I.D._607' [...]
+  var axesNames = ['DOB', 0, 1, 2, 3, 4];
+
+  var dm, ec;
+
+  function init() {
+    // Initialize the DecompositionModel
+    dm = new DecompositionModel(name, ids, coords, pct_var,
+                                md_headers, metadata, axesNames);
+    // Initialize the EmperorController
+    ec = new EmperorController(dm, 'emperor-notebook-0x9cb72f54');
+  }
+
+  function animate() {
+    requestAnimationFrame(animate);
+    ec.render();
+  }
+  $(window).resize(function() {
+    ec.resize(div.innerWidth(), div.innerHeight());
+  });
+
+  $(function(){
+    init();
+    animate();
+
+  });
+
+}); // END REQUIRE.JS block
+</script>"""
+
+
+MAP_PANDAS = """#SampleID	cat_a	cat_b	cat_c	num_1	num_2	num_3	num_4
+s1	foo	a	o	21	18	75	51
+s2	foo	b	p	3	42	44	36
+s3	bar	c	q	53	70	5	78
+s4	baz	d	r	47	13	72	72
+s5	FOO	e	s	13	50	1	56
+s6	FOO	f	o	13	56	39	5
+s7	foo	g	o	77	17	26	64
+s8	barosaurus	h	o	63	20	74	69
+s9	baz	i	p	20	32	39	16
+s10	baz	j	p	19	44	61	17
+s11	baz	k	q	47	25	37	42
+s12	baz	l	r	50	73	27	58
+s13	asdf	m	s	11	36	41	32
+s14	1234	n	s	9	32	42	25
+"""
diff --git a/tests/javascript_tests/index.html b/tests/javascript_tests/index.html
new file mode 100644
index 0000000..05a1eb1
--- /dev/null
+++ b/tests/javascript_tests/index.html
@@ -0,0 +1,210 @@
+<!--
+/**
+ *
+ * @author Yoshiki Vazquez Baeza
+ * @copyright Copyright 2013, The Emperor Project
+ * @credits Yoshiki Vazquez Baeza
+ * @license BSD
+ * @version 0.9.3-dev
+ * @maintainer Yoshiki Vazquez Baeza
+ * @email yoshiki89 at gmail.com
+ * @status Development
+ *
+ */
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+  <!--
+      Note that all of the resources listed in this file assume the standard
+      base structure of Emperor. It is likely that this will not work properly
+      if it's not executed as suggested.
+  -->
+  <title>Emperor test suite</title>
+  <link rel="stylesheet" href="qunit/qunit-min.css" type="text/css" media="screen">
+  <link rel="stylesheet" type="text/css" href="../../emperor/support_files/vendor/css/slick.grid.min.css">
+
+  <link rel="icon" href="../../emperor/support_files/img/favicon.ico">
+
+  <!-- Testing framework requirements -->
+  <script src="qunit/qunit-min.js"></script>
+
+  <!-- Qunit depends on jQuery -->
+  <script src="../../emperor/support_files/vendor/js/require-2.1.22.min.js"></script>
+
+</head>
+<body>
+  <div id="qunit"></div>
+  <div id="qunit-fixture">
+    <div id="map-test">
+      <div id="id1"></div>
+      <div id="id2"></div>
+    </div>
+  </div>
+  <br>
+  <h1 class="qunit-header">Emperor Test Suite</h1>
+  <p>
+    This test suite exercises all the functions that are used as part of
+    Emperor's front end. The functions that have direct interaction with the
+    instantiation of the user interface are not tested.
+  </p>
+  <script>
+    QUnit.config.autostart = false;
+
+    // Without this setTimeout, the specs don't always get execute in webKit
+    // browsers, this was taken from http://stackoverflow.com/q/13615679/379593
+    setTimeout(function () {
+      requirejs.config({
+        'baseUrl': '../../emperor/support_files/',
+
+        // the left side is the module name, and the right side is the path
+        // relative to the baseUrl attribute, do NOT include the .js extension
+        'paths': {
+          /* jQuery */
+          'jquery': './vendor/js/jquery-2.1.4.min',
+          'jqueryui': './vendor/js/jquery-ui.min',
+          'jquery_drag': './vendor/js/jquery.event.drag-2.2.min',
+
+          /* jQuery plugins */
+          'chosen': './vendor/js/chosen.jquery.min',
+          'spectrum': './vendor/js/spectrum.min',
+          'position': './vendor/js/jquery.ui.position.min',
+          'contextmenu': './vendor/js/jquery.contextMenu.min',
+
+          /* other libraries */
+          'underscore': './vendor/js/underscore-min',
+          'chroma': './vendor/js/chroma.min',
+          'd3': './vendor/js/d3.min',
+          'filesaver': './vendor/js/FileSaver.min',
+          'blob': './vendor/js/Blob',
+
+          /* THREE.js and plugins */
+          'three': './vendor/js/three.min',
+          'orbitcontrols': './vendor/js/three.js-plugins/OrbitControls',
+          'projector': './vendor/js/three.js-plugins/Projector',
+          'svgrenderer': './vendor/js/three.js-plugins/SVGRenderer',
+
+          /* SlickGrid */
+          'slickcore': './vendor/js/slick.core.min',
+          'slickgrid': './vendor/js/slick.grid.min',
+          'slickformatters': './vendor/js/slick.editors.min',
+          'slickeditors': './vendor/js/slick.formatters.min',
+
+          /* Emperor's objects */
+          'animate': './js/animate',
+          'color-editor': './js/color-editor',
+          'colorviewcontroller': './js/color-view-controller',
+          'scaleviewcontroller': './js/scale-view-controller',
+          'axescontroller': './js/axes-controller',
+          'scale-editor': './js/scale-editor',
+          'controller': './js/controller',
+          'draw': './js/draw',
+          'model': './js/model',
+          'scene3d': './js/sceneplotview3d',
+          'trajectory': './js/trajectory',
+          'util': './js/util',
+          'view': './js/view',
+          'abcviewcontroller': './js/abc-view-controller',
+          'viewcontroller': './js/view-controller',
+          'visibilitycontroller': './js/visibility-controller',
+          'shapecontroller': './js/shape-controller',
+          'shape-editor': './js/shape-editor',
+          'shapes': './js/shapes',
+
+          /* Tests */
+          'test_plottable': '../../tests/javascript_tests/test_plottable',
+          'test_animate': '../../tests/javascript_tests/test_animate',
+          'test_color_view_controller': '../../tests/javascript_tests/test_color_view_controller',
+          'test_scale_view_controller': '../../tests/javascript_tests/test_scale_view_controller',
+          'test_decomposition_model': '../../tests/javascript_tests/test_decomposition_model',
+          'test_decomposition_view': '../../tests/javascript_tests/test_decomposition_view',
+          'test_draw': '../../tests/javascript_tests/test_draw',
+          'test_plottable': '../../tests/javascript_tests/test_plottable',
+          'test_sceneplotview3d': '../../tests/javascript_tests/test_sceneplotview3d',
+          'test_trajectory': '../../tests/javascript_tests/test_trajectory',
+          'test_util': '../../tests/javascript_tests/test_util',
+          'test_view_controller': '../../tests/javascript_tests/test_view_controller',
+          'test_visibility_controller': '../../tests/javascript_tests/test_visibility_controller',
+          'test_shape_controller': '../../tests/javascript_tests/test_shape_controller',
+          'test_axes_controller': '../../tests/javascript_tests/test_axes_controller',
+        },
+        /*
+           Libraries that are not AMD compatible need shim to declare their
+           dependencies.
+         */
+        'shim': {
+          'jquery_drag': {
+            'deps': ['jquery', 'jqueryui']
+          },
+          'chosen': {
+            'deps': ['jquery'],
+            'exports': 'jQuery.fn.chosen'
+          },
+          'contextmenu' : {
+            'deps': ['jquery', 'jqueryui', 'position']
+          },
+          'filesaver' : {
+            'deps': ['blob']
+          },
+          'orbitcontrols': {
+            'deps': ['three']
+          },
+          'projector': {
+            'deps': ['three']
+          },
+          'svgrenderer': {
+            'deps': ['orbitcontrols', 'projector']
+          },
+        'slickcore': ['jqueryui'],
+        'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
+                      'slickeditors']
+        }
+      });
+
+      //load tests using require
+      require(
+          ['jquery', 'chosen', 'spectrum', 'position', 'contextmenu',
+           'underscore', 'chroma', 'three', 'orbitcontrols', 'projector',
+           'svgrenderer', 'slickgrid', 'animate', 'color-editor',
+           'colorviewcontroller', 'scaleviewcontroller', 'scale-editor',
+           'controller', 'draw', 'model', 'scene3d', 'trajectory', 'util',
+           'view', 'abcviewcontroller', 'viewcontroller',
+           'visibilitycontroller', 'shape-editor', 'shapes',
+
+           'test_plottable', 'test_decomposition_model',
+           'test_decomposition_view', 'test_view_controller',
+           'test_color_view_controller', 'test_sceneplotview3d',
+           'test_trajectory', 'test_animate', 'test_util',  'test_draw',
+           'test_visibility_controller', 'test_shape_controller',
+           'test_axes_controller'],
+           /*
+              Very important to always load all dependencies first, otherwise
+              you might encounter problems with Qunit not running all tests.
+            */
+            function ($, chosen, spectrum, position,
+                      contextmenu, underscore, chroma, three,
+                      orbitcontrols, projector, svgrenderer, slickgrid,
+                      animate, coloreditor, colorviewcontroller,
+                      scaleviewcontroller, scaleeditor, controller,
+                      draw, model, scene3d, trajectory, util, view,
+                      abcviewcontroller, viewcontroller, visibilitycontroller,
+                      shapeeditor, shapes,
+
+                      // test suites
+                      test_plottable, test_decomposition_model,
+                      test_decomposition_view, test_view_controller,
+                      test_color_view_controller, test_sceneplotview3d,
+                      test_trajectory, test_animate, test_util, test_ui,
+                      test_draw, test_visibility_controller,
+                      test_shape_controller, test_scale_view_controller,
+                      test_axes_controller) {
+              // now trigger the tests
+              $( document ).ready(function() {
+                QUnit.start();
+              });
+      });
+    }, 10);
+  </script>
+</body>
+</html>
diff --git a/tests/javascript_tests/qunit/qunit-min.css b/tests/javascript_tests/qunit/qunit-min.css
new file mode 100644
index 0000000..dd63ae3
--- /dev/null
+++ b/tests/javascript_tests/qunit/qunit-min.css
@@ -0,0 +1,11 @@
+/**
+ * QUnit v1.12.0 - A JavaScript Unit Testing Framework
+ *
+ * http://qunitjs.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ * minified using http://cssminifier.com
+ */
+#qunit-banner,#qunit-header,#qunit-testresult,#qunit-testrunner-toolbar,#qunit-tests,#qunit-userAgent{font-family:"Helvetica Neue Light",HelveticaNeue-Light,"Helvetica Neue",Calibri,Helvetica,Arial,sans-serif}#qunit-testresult,#qunit-testrunner-toolbar,#qunit-tests li,#qunit-userAgent{font-size:small}#qunit-tests{font-size:smaller}#qunit-banner,#qunit-header,#qunit-modulefilter,#qunit-testresult,#qunit-tests,#qunit-userAgent{margin:0;padding:0}#qunit-header{padding:.5em 0 .5em 1em;color: [...]
\ No newline at end of file
diff --git a/tests/javascript_tests/qunit/qunit-min.js b/tests/javascript_tests/qunit/qunit-min.js
new file mode 100644
index 0000000..23ac26b
--- /dev/null
+++ b/tests/javascript_tests/qunit/qunit-min.js
@@ -0,0 +1,11 @@
+/**
+ * QUnit v1.12.0 - A JavaScript Unit Testing Framework
+ *
+ * http://qunitjs.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * https://jquery.org/license/
+ * minified using http://jscompress.com
+ */
+(function(e){function d(e){N(this,e);this.assertions=[];this.testNumber=++d.count}function v(){r.autorun=true;if(r.currentModule){D("moduleDone",t,{name:r.currentModule,failed:r.moduleStats.bad,passed:r.moduleStats.all-r.moduleStats.bad,total:r.moduleStats.all})}delete r.previousModule;var n,i,s=M("qunit-banner"),o=M("qunit-tests"),u=+(new f)-r.started,a=r.stats.all-r.stats.bad,l=["Tests completed in ",u," milliseconds.<br/>","<span class='passed'>",a,"</span> assertions of <span class=' [...]
\ No newline at end of file
diff --git a/tests/javascript_tests/runner.js b/tests/javascript_tests/runner.js
new file mode 100644
index 0000000..b47418d
--- /dev/null
+++ b/tests/javascript_tests/runner.js
@@ -0,0 +1,165 @@
+/*
+ *
+ * QtWebKit-powered headless test runner using PhantomJS
+ *
+ * PhantomJS binaries: http://phantomjs.org/download.html
+ * Requires PhantomJS 1.6+ (1.7+ recommended)
+ *
+ * Run with:
+ *   phantomjs runner.js [url-of-your-qunit-testsuite]
+ *
+ * e.g.
+ *   phantomjs runner.js http://localhost/qunit/test/index.html
+ *
+ * Originally taken from underscore.js https://github.com/jashkenas/underscore
+ * SHA-1 b5f074ff72f949c2548605354e6c739df7ba73aa
+ *
+ */
+
+/*jshint latedef:false */
+/*global phantom:false, require:false, console:false, window:false,
+  QUnit:false */
+
+(function() {
+    'use strict';
+
+    var args = require('system').args;
+
+    // arg[0]: scriptName, args[1...]: arguments
+    if (args.length !== 2) {
+        console.error('Usage:\n  phantomjs runner.js ' +
+                      '[url-of-your-qunit-testsuite]');
+        exit(1);
+    }
+
+    var url = args[1],
+        page = require('webpage').create();
+
+    // Route `console.log()` calls from within the Page context to the main
+    // Phantom context (i.e. current `this`)
+    page.onConsoleMessage = function(msg) {
+        console.log(msg);
+    };
+
+    page.onInitialized = function() {
+        page.evaluate(addLogging);
+    };
+
+    page.onCallback = function(message) {
+        var result,
+            failed;
+
+        if (message) {
+            if (message.name === 'QUnit.done') {
+                result = message.data;
+                failed = !result || result.failed;
+
+                exit(failed ? 1 : 0);
+            }
+        }
+    };
+
+    page.open(url, function(status) {
+        if (status !== 'success') {
+            console.error('Unable to access network: ' + status);
+            exit(1);
+        } else {
+            // Cannot do this verification with the 'DOMContentLoaded' handler
+            // because it will be too late to attach it if a page does not have
+            // any script tags.
+            var qunitMissing = page.evaluate(function() {
+                return (typeof QUnit === 'undefined' || !QUnit);
+            });
+            if (qunitMissing) {
+                console.error('The `QUnit` object is not present.');
+                exit(1);
+            }
+
+            // Do nothing... the callback mechanism will handle everything!
+        }
+    });
+
+    function addLogging() {
+        window.document.addEventListener('DOMContentLoaded', function() {
+            var cur_test_asserts = [];
+
+            QUnit.log(function(details) {
+                var response;
+
+                // Ignore passing assertions
+                if (details.result) {
+                    return;
+                }
+
+                response = details.message || '';
+
+                if (typeof details.expected !== 'undefined') {
+                    if (response) {
+                        response += ', ';
+                    }
+
+                    response += 'expected: ' + details.expected +
+                    ', but was: ' + details.actual;
+                    if (details.source) {
+                        response += '\n' + details.source;
+                    }
+                }
+
+                cur_test_asserts.push('Failed assertion: ' + response);
+            });
+
+            QUnit.testDone(function(result) {
+                var i,
+                    len,
+                    name = result.module + ': ' + result.name;
+
+                if (result.failed) {
+                    console.log('Test failed: ' + name);
+
+                    for (i = 0, len = cur_test_asserts.length; i < len; i++) {
+                        console.log('    ' + cur_test_asserts[i]);
+                    }
+                }
+                else {
+                    console.log(name + ' (' + result.duration + ' ms) ... ok');
+                }
+
+                cur_test_asserts.length = 0;
+            });
+
+            QUnit.moduleDone(function(result) {
+                console.log('');
+            });
+
+            QUnit.done(function(result) {
+                console.log('Took ' + result.runtime + 'ms to run ' +
+                            result.total + ' tests. ' + result.passed +
+                            ' passed, ' + result.failed + ' failed.');
+
+                if (typeof window.callPhantom === 'function') {
+                    window.callPhantom({
+                        'name': 'QUnit.done',
+                        'data': result
+                    });
+                }
+            });
+        }, false);
+    }
+
+    /*
+     This function was taken from:
+     https://github.com/jonkemp/qunit-phantomjs-runner
+
+     It helps prevent some problems with the output produced by this script.
+     */
+    function exit(code) {
+        if (page) {
+            page.close();
+        }
+        setTimeout(function() {
+            phantom.exit(code);
+        }, 0);
+    }
+
+
+})();
diff --git a/tests/javascript_tests/test_animate.js b/tests/javascript_tests/test_animate.js
new file mode 100644
index 0000000..48e3f64
--- /dev/null
+++ b/tests/javascript_tests/test_animate.js
@@ -0,0 +1,328 @@
+requirejs([
+    'underscore',
+    'jquery',
+    'animate'
+], function(_, $, AnimationDirector) {
+  $(document).ready(function() {
+
+    // these variables are reused throughout this test suite
+    var mappingFileHeaders, mappingFileData, coordinatesData;
+
+    module('Animate', {
+
+      setup: function() {
+        // setup function
+        mappingFileHeaders = ['SampleID', 'LinkerPrimerSequence', 'Treatment',
+                              'DOB'];
+        mappingFileData = {
+          'PC.481': ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+          'PC.607': ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+          'PC.634': ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.635': ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.593': ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+          'PC.636': ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.355': ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+          'PC.354': ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+          'PC.356': ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126']
+        };
+        coordinatesData = new Array();
+        coordinatesData['PC.636'] = { 'name': 'PC.636', 'color': 0, 'x':
+        -0.276542, 'y': -0.144964, 'z': 0.066647, 'P1': -0.276542, 'P2':
+        -0.144964, 'P3': 0.066647, 'P4': -0.067711, 'P5': 0.176070, 'P6':
+        0.072969, 'P7': -0.229889, 'P8': -0.046599 };
+        coordinatesData['PC.635'] = { 'name': 'PC.635', 'color': 0, 'x':
+        -0.237661, 'y': 0.046053, 'z': -0.138136, 'P1': -0.237661, 'P2':
+        0.046053, 'P3': -0.138136, 'P4': 0.159061, 'P5': -0.247485, 'P6':
+        -0.115211, 'P7': -0.112864, 'P8': 0.064794 };
+        coordinatesData['PC.356'] = { 'name': 'PC.356', 'color': 0, 'x':
+        0.228820, 'y': -0.130142, 'z': -0.287149, 'P1': 0.228820, 'P2':
+        -0.130142, 'P3': -0.287149, 'P4': 0.086450, 'P5': 0.044295, 'P6':
+        0.206043, 'P7': 0.031000, 'P8': 0.071992 };
+
+        coordinatesData['PC.481'] = { 'name': 'PC.481', 'color': 0, 'x':
+        0.042263, 'y': -0.013968, 'z': 0.063531, 'P1': 0.042263, 'P2':
+        -0.013968, 'P3': 0.063531, 'P4': -0.346121, 'P5': -0.127814, 'P6':
+        0.013935, 'P7': 0.030021, 'P8': 0.140148 }; coordinatesData['PC.354'] =
+        { 'name': 'PC.354', 'color': 0, 'x': 0.280399, 'y': -0.006013, 'z':
+        0.023485, 'P1': 0.280399, 'P2': -0.006013, 'P3': 0.023485, 'P4':
+        -0.046811, 'P5': -0.146624, 'P6': 0.005670, 'P7': -0.035430, 'P8':
+        -0.255786 };
+        coordinatesData['PC.593'] = { 'name': 'PC.593', 'color': 0,
+        'x': 0.232873, 'y': 0.139788, 'z': 0.322871, 'P1': 0.232873, 'P2':
+        0.139788, 'P3': 0.322871, 'P4': 0.183347, 'P5': 0.020466, 'P6':
+        0.054059, 'P7': -0.036625, 'P8': 0.099824 };
+        coordinatesData['PC.355'] = { 'name': 'PC.355', 'color': 0, 'x':
+        0.170518, 'y': -0.194113, 'z': -0.030897, 'P1': 0.170518, 'P2':
+        -0.194113, 'P3': -0.030897, 'P4': 0.019809, 'P5': 0.155100, 'P6':
+        -0.279924, 'P7': 0.057609, 'P8': 0.024248 };
+        coordinatesData['PC.607'] = { 'name': 'PC.607', 'color': 0,
+        'x': -0.091330, 'y': 0.424147, 'z': -0.135627, 'P1': -0.091330, 'P2':
+        0.424147, 'P3': -0.135627, 'P4': -0.057519, 'P5': 0.151363, 'P6':
+        -0.025394, 'P7': 0.051731, 'P8': -0.038738 };
+        coordinatesData['PC.634'] = { 'name': 'PC.634', 'color': 0,
+        'x': -0.349339, 'y': -0.120788, 'z': 0.115275, 'P1': -0.349339,
+        'P2': -0.120788, 'P3': 0.115275, 'P4': 0.069495, 'P5': -0.025372,
+        'P6': 0.067853, 'P7': 0.244448, 'P8': -0.059883 };
+
+        mappingFileDataShort = { 'PC.481': ['PC.481', 'YATGCTGCCTCCCGTAGGAGT',
+        'Control', '20070314'], 'PC.635': ['PC.635', 'YATGCTGCCTCCCGTAGGAGT',
+        'Fast', '20080116'], 'PC.636': ['PC.636', 'YATGCTGCCTCCCGTAGGAGT',
+        'Fast', '20080116'], 'PC.356': ['PC.356', 'YATGCTGCCTCCCGTAGGAGT',
+        'Fast', '20061126'] };
+        coordinatesDataShort = new Array();
+        coordinatesDataShort['PC.636'] = { 'name': 'PC.636', 'color': 0, 'x':
+        -0.276542, 'y': -0.144964, 'z': 0.066647, 'P1': -0.276542, 'P2':
+        -0.144964, 'P3': 0.066647, 'P4': -0.067711, 'P5': 0.176070, 'P6':
+        0.072969, 'P7': -0.229889, 'P8': -0.046599 };
+        coordinatesDataShort['PC.635'] = { 'name': 'PC.635', 'color': 0, 'x':
+        -0.237661, 'y': 0.046053, 'z': -0.138136, 'P1': -0.237661, 'P2':
+        0.046053, 'P3': -0.138136, 'P4': 0.159061, 'P5': -0.247485, 'P6':
+        -0.115211, 'P7': -0.112864, 'P8': 0.064794 };
+        coordinatesDataShort['PC.356'] = { 'name': 'PC.356', 'color': 0, 'x':
+        0.228820, 'y': -0.130142, 'z': -0.287149, 'P1': 0.228820, 'P2':
+        -0.130142, 'P3': -0.287149, 'P4': 0.086450, 'P5': 0.044295, 'P6':
+        0.206043, 'P7': 0.031000, 'P8': 0.071992 };
+        coordinatesDataShort['PC.481'] = { 'name': 'PC.481', 'color': 0, 'x':
+        0.042263, 'y': -0.013968, 'z': 0.063531, 'P1': 0.042263, 'P2':
+        -0.013968, 'P3': 0.063531, 'P4': -0.346121, 'P5': -0.127814, 'P6':
+        0.013935, 'P7': 0.030021, 'P8': 0.140148 };
+
+        // trajectories with only one unique timepoint in different cases
+        // (1) all timepoints with the same value
+        // (2) a single timepoint
+        mappingFileHeadersUnique = ['SampleID', 'LinkerPrimerSequence',
+                                    'Treatment', 'DOB'];
+        mappingFileDataUnique = {
+          'PC.481': ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'A', '0'],
+          'PC.607': ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'B', '0'],
+          'PC.634': ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'B', '0'],
+          'PC.635': ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'C', '0'],
+          'PC.593': ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', 'C', '1'],
+          'PC.636': ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'C', '2'],
+          'PC.355': ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'D', '-9999'],
+          'PC.354': ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'D', '0'],
+          'PC.356': ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'D', '100000'] };
+      },
+
+      teardown: function() {
+        // teardown function
+        mappingFileHeaders = null;
+        mappingFileData = null;
+        coordinatesData = null;
+      }
+
+    });
+
+    /**
+     *
+     * Test that the animation object can be constructed without any problems
+     * and check that the attributes are set correctly.
+     *
+     */
+    test('Test constructor', function() {
+
+      var director = new AnimationDirector(mappingFileHeaders, mappingFileData,
+          coordinatesData, 'DOB',
+          'Treatment', 1000, 10);
+
+      // a quick run through all the properties
+      equal(director.mappingFileHeaders, mappingFileHeaders, 'The mapping ' +
+          'file headers are set correctly');
+      equal(director.mappingFileData, mappingFileData, 'The mapping file ' +
+          'data is set correctly');
+      equal(director.coordinatesData, coordinatesData, 'The coordinates data' +
+          ' is set correctly');
+      equal(director.gradientCategory, 'DOB', 'The gradientCategory is set' +
+          ' correctly');
+      equal(director.trajectoryCategory, 'Treatment', 'The ' +
+          'trajectoryCategory is set correctly');
+      equal(director.minimumDelta, 92, 'The minimum delta is computed' +
+          'correctly');
+      equal(director.maximumTrajectoryLength, 26, 'The maximum trajectory ' +
+          'length value is correct');
+      equal(director.currentFrame, -1, 'The current frame is correct');
+      equal(director.trajectories.length, 2, 'The number of trajectories is ' +
+          'correct');
+      equal(director.trajectories[0].metadataCategoryName, 'Control', 'The' +
+          'metadata category name is set correctly for the trajectory 1');
+      equal(director.trajectories[1].metadataCategoryName, 'Fast', 'The' +
+          'metadata category name is set correctly for the trajectory 1');
+
+      // check the trajectories are overall ok -- reason why I added this,
+      // because they are not :P
+      deepEqual(director.trajectories[0].representativeCoordinatesAtIndex(1000),
+          [{'x': 0.22882, 'y': -0.130142, 'z': -0.287149},
+          {'x': 0.170518, 'y': -0.194113, 'z': -0.030897},
+          {'x': 0.280399, 'y': -0.006013, 'z': 0.023485},
+          {'x': 0.042263, 'y': -0.013968, 'z': 0.063531},
+          {'x': 0.232873, 'y': 0.139788, 'z': 0.322871}],
+          'Control');
+      deepEqual(director.trajectories[1].representativeCoordinatesAtIndex(1000),
+          [{'x': -0.09133, 'y': 0.424147, 'z': -0.135627},
+          {'x': -0.349339, 'y': -0.120788, 'z': 0.115275},
+          {'x': -0.237661, 'y': 0.046053, 'z': -0.138136},
+          {'x': -0.276542, 'y': -0.144964, 'z': 0.066647}],
+          'Fast');
+      equal(director.trajectories.length, 2, 'The number of trajectories is ' +
+          'correct');
+    });
+
+    test('Test useless trajectories are removed', function() {
+      var director = new AnimationDirector(mappingFileHeadersUnique,
+          mappingFileDataUnique,
+          coordinatesData, 'DOB',
+          'Treatment', 1000, 10);
+      equal(director.trajectories.length, 2, 'The number of trajectories is ' +
+          'correct');
+      equal(director.trajectories[0].metadataCategoryName, 'C', 'The ' +
+          'category name (C) is assigned correctly');
+      equal(director.trajectories[1].metadataCategoryName, 'D', 'The ' +
+          'category name (D) is assigned correctly');
+      deepEqual(director.trajectories[0].gradientPoints,
+          ['0', '1', '2'], 'Correct time points (C)');
+        deepEqual(director.trajectories[1].gradientPoints,
+            ['-9999', '0', '100000'], 'Correct time points (D)');
+    });
+
+    /**
+     *
+     * Test that the animation object cannot be constructed when there are
+     * missing arguments.
+     *
+     */
+    test('Test constructor exceptions', function() {
+      var result;
+
+      // check this happens for all the properties
+      throws(
+          function() {
+            result = new AnimationDirector(mappingFileData, coordinatesData,
+                'DOB', 'Treatment', 1000);
+          },
+          Error,
+          'An error is raised if mapping file headers are not passed'
+          );
+
+      throws(
+          function() {
+            result = new AnimationDirector(mappingFileHeaders,
+                coordinatesData, 'DOB',
+                'Treatment', 1000);
+          },
+          Error,
+          'An error is raised if mapping file data is not passed'
+          );
+
+      throws(
+          function() {
+            result = new AnimationDirector(mappingFileHeaders,
+                mappingFileData, coordinatesData,
+                'Treatment', 1000);
+          },
+          Error,
+          'An error is raised if no gradient category is passed'
+          );
+
+      throws(
+          function() {
+            result = new AnimationDirector(mappingFileHeaders,
+                mappingFileData, 'DOB', 1000);
+          },
+          Error,
+          'An error is raised if no trajectory category is passed'
+          );
+
+      throws(
+          function() {
+            result = new AnimationDirector(mappingFileHeaders, mappingFileData,
+                'DOB', 'Treatment');
+          },
+          Error,
+          'An error is raised if no the number of frames is not passed'
+          );
+    });
+
+    /**
+     *
+     * Test that the animation object getMaximumTrajectoryLength method returns
+     * the correct value for different cases.
+     *
+     */
+    test('Test maximum trajectory length method', function() {
+
+      var director = new AnimationDirector(mappingFileHeaders, mappingFileData,
+          coordinatesData, 'DOB',
+          'Treatment', 1000);
+      equal(director.getMaximumTrajectoryLength(), 26,
+          'Test for the correct getMaximumTrajectoryLength value to be ' +
+          'returned');
+      var director = new AnimationDirector(mappingFileHeaders, mappingFileData,
+          coordinatesData, 'DOB',
+          'Treatment', 10000);
+      equal(director.getMaximumTrajectoryLength(), 26,
+          'Test for the correct getMaximumTrajectoryLength value to be ' +
+          'returned');
+      var director = new AnimationDirector(mappingFileHeaders,
+          mappingFileData, coordinatesData,
+          'DOB', 'LinkerPrimerSequence',
+          1000);
+      equal(director.getMaximumTrajectoryLength(), 41,
+          'Test for the correct getMaximumTrajectoryLength value to be ' +
+          'returned');
+    });
+
+    /**
+     *
+     * Test that the animation object updateFrame method updates the value only
+     * when needed.
+     *
+     */
+    test('Test the current frame is updated correctly', function() {
+      var director = new AnimationDirector(mappingFileHeaders,
+          mappingFileData, coordinatesData,
+          'DOB', 'Treatment', 1000);
+      equal(director.currentFrame, -1, 'The current frame is set correctly');
+      director.updateFrame();
+      equal(director.currentFrame, 0, 'The current frame is set correctly');
+
+      // make sure the value is topped at the maximum trajectory length
+      for (var i = 1; i < 1000; i++) {
+        director.updateFrame();
+      }
+      equal(director.currentFrame, 27, 'The current frame is stopped at the' +
+          ' maximum trajectory length');
+    });
+
+    /**
+     *
+     * Test that the animation object gets the correct number of trajectories.
+     *
+     */
+    test('Test the trajectories are initialized correctly', function() {
+      var director = new AnimationDirector(mappingFileHeaders,
+          mappingFileData, coordinatesData,
+          'DOB', 'Treatment', 1000);
+      equal(director.trajectories.length, 2, 'Correct number of trajectories');
+
+      var director = new AnimationDirector(mappingFileHeaders, mappingFileData,
+          coordinatesData, 'DOB',
+          'LinkerPrimerSequence', 1000);
+      equal(director.trajectories.length, 1, 'Correct number of trajectories');
+
+    });
+
+    /**
+     *
+     * Test that the animation object ignores one-sample trajectories
+     *
+     */
+    test('Test that tricky trajectories are initialized correctly', function() {
+      var director = new AnimationDirector(mappingFileHeaders,
+          mappingFileDataShort,
+          coordinatesDataShort,
+          'DOB', 'Treatment', 1000);
+      equal(director.trajectories.length, 1, 'Correct number of trajectories');
+
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_axes_controller.js b/tests/javascript_tests/test_axes_controller.js
new file mode 100644
index 0000000..0ba7e61
--- /dev/null
+++ b/tests/javascript_tests/test_axes_controller.js
@@ -0,0 +1,146 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'abcviewcontroller',
+    'slickgrid',
+    'axescontroller'
+], function($, _, model, DecompositionView, abc, SlickGrid,
+            AxesController) {
+  $(document).ready(function() {
+    var EmperorViewControllerABC = abc.EmperorViewControllerABC;
+    var DecompositionModel = model.DecompositionModel;
+
+    module('AxesController', {
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+        var $slickid = $('<div id="fooligans"></div>');
+        $slickid.appendTo(document.body);
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635', 'PC.634'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Mixed', 'Treatment', 'DOB'];
+        metadata = [['PC.636', '14.2', 'Control', '20070314'],
+        ['PC.635', 'StringValue', 'Fast', '20071112'],
+        ['PC.634', '14.7', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        this.decomp = new DecompositionModel(name, ids, coords, pct_var,
+            md_headers, metadata);
+        this.dv = new DecompositionView(this.decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+
+        // Slickgrid
+        var columns = [
+        {id: 'pc1', name: 'pc1', field: 'pc1'},
+        {id: 'pc2', name: 'pc2', field: 'pc2'},
+        {id: 'pc3', name: 'pc3', field: 'pc3'}
+        ];
+
+        var options = {
+          enableCellNavigation: true,
+          enableColumnReorder: false
+        };
+        var data = [];
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 1});
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 2});
+        data.push({'pc1': 2, 'pc2': 1, 'pc3': 2});
+
+        grid = new Slick.Grid('#fooligans', data, columns, options);
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        $('#fooligans').remove();
+        this.decomp = undefined;
+      }
+    });
+
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="does-not-exist" style="height:1000px; ' +
+                        'width:12px"></div>');
+
+      assert.ok(AxesController.prototype instanceof EmperorViewControllerABC);
+
+      var controller = new AxesController(
+        container, this.sharedDecompositionViewDict);
+      equal(controller.title, 'Axes');
+
+      deepEqual(controller._flippedAxes, [0, 0, 0]);
+      equal(controller.$_screePlotContainer.attr('name'), 'scree-plot');
+
+      equal(controller.$body.find('[name="axes-color"]').length, 1);
+      equal(controller.$body.find('[name="background-color"]').length, 1);
+    });
+
+    test('Testing toJSON', function() {
+      var container = $('<div id="does-not-exist" style="height:1000px; ' +
+                        'width:12px"></div>');
+      var controller = new AxesController(
+        container, this.sharedDecompositionViewDict);
+
+      var obs = controller.toJSON();
+      var exp = {'flippedAxes': [0, 0, 0], 'visibleDimensions': [0, 1, 2],
+                 'backgroundColor': 0x000000, 'axesColor': 0xFFFFFF};
+      deepEqual(obs, exp);
+    });
+
+    test('Testing fromJSON', function() {
+      var json = {'flippedAxes': [1, 1, 0], 'visibleDimensions': [0, 1, 0],
+                  'backgroundColor': 0xFF00FF, 'axesColor': 0xFF000F};
+
+      var container = $('<div id="does-not-exist" style="height:1000px; ' +
+                        'width:12px"></div>');
+      var controller = new AxesController(
+        container, this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+
+      var decView = controller.decompViewDict[controller.activeViewKey];
+      deepEqual(decView.visibleDimensions, [0, 1, 0]);
+      deepEqual(controller._flippedAxes, [1, 1, 0]);
+
+      deepEqual(decView.backgroundColor, 0xFF00FF);
+      deepEqual(decView.axesColor, 0xFF000F);
+    });
+
+    test('Testing colorChanged', function() {
+      var container = $('<div id="does-not-exist" style="height:1000px; ' +
+                        'width:12px"></div>');
+      var controller = new AxesController(
+        container, this.sharedDecompositionViewDict);
+
+      var decView = controller.decompViewDict[controller.activeViewKey];
+      controller.colorChanged('axes-color', 0xF0F0F0);
+      deepEqual(decView.axesColor, 0xF0F0F0);
+      controller.colorChanged('background-color', 0x101010);
+      deepEqual(decView.backgroundColor, 0x101010);
+    });
+
+  });
+});
diff --git a/tests/javascript_tests/test_color_view_controller.js b/tests/javascript_tests/test_color_view_controller.js
new file mode 100644
index 0000000..eb14e2f
--- /dev/null
+++ b/tests/javascript_tests/test_color_view_controller.js
@@ -0,0 +1,544 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'viewcontroller',
+    'slickgrid',
+    'colorviewcontroller'
+], function($, _, model, DecompositionView, viewcontroller, SlickGrid,
+            ColorViewController) {
+  $(document).ready(function() {
+    var EmperorAttributeABC = viewcontroller.EmperorAttributeABC;
+    var DecompositionModel = model.DecompositionModel;
+    var Plottable = model.Plottable;
+
+    module('ColorViewController', {
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+        var $slickid = $('<div id="fooligans"></div>');
+        $slickid.appendTo(document.body);
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635', 'PC.634'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Mixed', 'Treatment', 'DOB'];
+        metadata = [['PC.636', '14.2', 'Control', '20070314'],
+        ['PC.635', 'StringValue', 'Fast', '20071112'],
+        ['PC.634', '14.7', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        this.decomp = new DecompositionModel(name, ids, coords, pct_var,
+                                             md_headers, metadata);
+        this.dv = new DecompositionView(this.decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+
+        // Slickgrid
+        var columns = [
+        {id: 'pc1', name: 'pc1', field: 'pc1'},
+        {id: 'pc2', name: 'pc2', field: 'pc2'},
+        {id: 'pc3', name: 'pc3', field: 'pc3'}
+        ];
+
+        var options = {
+          enableCellNavigation: true,
+          enableColumnReorder: false
+        };
+        var data = [];
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 1});
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 2});
+        data.push({'pc1': 2, 'pc2': 1, 'pc3': 2});
+
+        grid = new Slick.Grid('#fooligans', data, columns, options);
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        $('#fooligans').remove();
+        this.decomp = undefined;
+      }
+    });
+
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="no-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+
+      assert.ok(ColorViewController.prototype instanceof EmperorAttributeABC);
+
+      var controller = new ColorViewController(
+        container, this.sharedDecompositionViewDict);
+      equal(controller.title, 'Color');
+
+      var testColumn = controller.bodyGrid.getColumns()[0];
+      equal(testColumn.field, 'value');
+
+      // verify the color value is set properly
+      equal(controller.$colormapSelect.val(), 'discrete-coloring-qiime');
+      equal(controller.$select.val(), 'SampleID');
+    });
+
+    test('Test _nonNumericPlottables', function() {
+      var container = $('<div id="no-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ColorViewController(
+        container, this.sharedDecompositionViewDict);
+      var k = controller.getActiveDecompViewKey();
+      var decompViewDict = controller.decompViewDict[k];
+
+      var colors = {'14.7': '#f7fbff',
+                    '14.2': '#f3f8fd',
+                    'StringValue': '#e8f2fd'};
+      var data = decompViewDict.setCategory(
+        colors, ColorViewController.prototype.setPlottableAttributes, 'Mixed');
+      var uniqueVars = ['14.7', '14.2', 'StringValue'];
+
+      // Test all are string
+      ColorViewController._nonNumericPlottables(uniqueVars, data);
+      var plottables = ColorViewController._nonNumericPlottables(uniqueVars,
+                                                                 data);
+      var exp = [
+        new Plottable(
+            'PC.635',
+            ['PC.635', 'StringValue', 'Fast', '20071112'],
+            [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+            -0.112864, 0.064794],
+            1)
+        ];
+      deepEqual(plottables, exp);
+
+      // Test all are numeric
+      var colors = {'20070314': '#f7fbff', '20071112': '#f3f8fd'};
+      var data = decompViewDict.setCategory(
+        colors, ColorViewController.prototype.setPlottableAttributes, 'DOB');
+      var uniqueVars = ['20070314', '20071112'];
+      var plottables = ColorViewController._nonNumericPlottables(uniqueVars,
+                                                                 data);
+      deepEqual(plottables, []);
+    });
+
+    test('Test discrete colors are retrieved correctly', function() {
+      deepEqual(ColorViewController.getDiscreteColors([0, 1, 2]),
+                {0: '#ff0000', 1: '#0000ff', 2: '#f27304'});
+    });
+
+    test('Test discrete colors are retrieved on roll-over', function() {
+      var fifteen = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
+      var obs = ColorViewController.getDiscreteColors(fifteen, 'Pastel1');
+      var exp = {'0': '#fbb4ae', '1': '#b3cde3', '2': '#ccebc5',
+                 '3': '#decbe4', '4': '#fed9a6', '5': '#ffffcc',
+                 '6': '#e5d8bd', '7': '#fddaec', '8': '#f2f2f2',
+                 '9': '#fbb4ae', '10': '#b3cde3', '11': '#ccebc5',
+                 '12': '#decbe4', '13': '#fed9a6', '14': '#ffffcc'};
+      deepEqual(obs, exp);
+    });
+
+    test('Test discrete colors with other maps', function() {
+      deepEqual(ColorViewController.getDiscreteColors([0], 'Set1'),
+                {0: '#e41a1c'});
+    });
+
+
+    test('Test getScaledColors', function() {
+      var five = ['0', '1', '2', '3', '4'];
+      var color = ColorViewController.getScaledColors(five, 'Viridis');
+      deepEqual(color, [{0: '#440154', 1: '#3f4a8a', 2: '#26838f',
+                         3: '#6cce5a', 4: '#fee825'},
+        '<defs><linearGradient id="Gradient" x1="0" x2="0" y1="1" y2="0">' +
+        '<stop offset="0%" stop-color="#440154"/>' +
+        '<stop offset="1%" stop-color="#440456"/>' +
+        '<stop offset="2%" stop-color="#440759"/>' +
+        '<stop offset="3%" stop-color="#440a5c"/>' +
+        '<stop offset="4%" stop-color="#450d5f"/>' +
+        '<stop offset="5%" stop-color="#451062"/>' +
+        '<stop offset="6%" stop-color="#451364"/>' +
+        '<stop offset="7%" stop-color="#461667"/>' +
+        '<stop offset="8%" stop-color="#46196a"/>' +
+        '<stop offset="9%" stop-color="#461c6d"/>' +
+        '<stop offset="10%" stop-color="#471f70"/>' +
+        '<stop offset="11%" stop-color="#472272"/>' +
+        '<stop offset="12%" stop-color="#472575"/>' +
+        '<stop offset="13%" stop-color="#472877"/>' +
+        '<stop offset="14%" stop-color="#462b79"/>' +
+        '<stop offset="15%" stop-color="#462e7a"/>' +
+        '<stop offset="16%" stop-color="#45307c"/>' +
+        '<stop offset="17%" stop-color="#44337d"/>' +
+        '<stop offset="18%" stop-color="#44367f"/>' +
+        '<stop offset="19%" stop-color="#433980"/>' +
+        '<stop offset="20%" stop-color="#423c82"/>' +
+        '<stop offset="21%" stop-color="#413e83"/>' +
+        '<stop offset="22%" stop-color="#414185"/>' +
+        '<stop offset="23%" stop-color="#404486"/>' +
+        '<stop offset="24%" stop-color="#3f4788"/>' +
+        '<stop offset="25%" stop-color="#3f4a8a"/>' +
+        '<stop offset="26%" stop-color="#3d4c8a"/>' +
+        '<stop offset="27%" stop-color="#3c4e8a"/>' +
+        '<stop offset="28%" stop-color="#3b508a"/>' +
+        '<stop offset="29%" stop-color="#3a538b"/>' +
+        '<stop offset="30%" stop-color="#39558b"/>' +
+        '<stop offset="31%" stop-color="#38578b"/>' +
+        '<stop offset="32%" stop-color="#375a8c"/>' +
+        '<stop offset="33%" stop-color="#365c8c"/>' +
+        '<stop offset="34%" stop-color="#345e8c"/>' +
+        '<stop offset="35%" stop-color="#33618d"/>' +
+        '<stop offset="36%" stop-color="#32638d"/>' +
+        '<stop offset="37%" stop-color="#31658d"/>' +
+        '<stop offset="38%" stop-color="#30688e"/>' +
+        '<stop offset="39%" stop-color="#2f6a8e"/>' +
+        '<stop offset="40%" stop-color="#2e6c8e"/>' +
+        '<stop offset="41%" stop-color="#2d6e8e"/>' +
+        '<stop offset="42%" stop-color="#2d718e"/>' +
+        '<stop offset="43%" stop-color="#2c738e"/>' +
+        '<stop offset="44%" stop-color="#2b758e"/>' +
+        '<stop offset="45%" stop-color="#2a778e"/>' +
+        '<stop offset="46%" stop-color="#297a8e"/>' +
+        '<stop offset="47%" stop-color="#287c8e"/>' +
+        '<stop offset="48%" stop-color="#277e8e"/>' +
+        '<stop offset="49%" stop-color="#26808e"/>' +
+        '<stop offset="50%" stop-color="#26838f"/>' +
+        '<stop offset="51%" stop-color="#25858e"/>' +
+        '<stop offset="52%" stop-color="#24878e"/>' +
+        '<stop offset="53%" stop-color="#24898d"/>' +
+        '<stop offset="54%" stop-color="#238b8d"/>' +
+        '<stop offset="55%" stop-color="#238d8d"/>' +
+        '<stop offset="56%" stop-color="#228f8c"/>' +
+        '<stop offset="57%" stop-color="#22918c"/>' +
+        '<stop offset="58%" stop-color="#21938b"/>' +
+        '<stop offset="59%" stop-color="#20958b"/>' +
+        '<stop offset="60%" stop-color="#20978b"/>' +
+        '<stop offset="61%" stop-color="#1f998a"/>' +
+        '<stop offset="62%" stop-color="#1f9b8a"/>' +
+        '<stop offset="63%" stop-color="#229e88"/>' +
+        '<stop offset="64%" stop-color="#28a284"/>' +
+        '<stop offset="65%" stop-color="#2ea680"/>' +
+        '<stop offset="66%" stop-color="#34aa7c"/>' +
+        '<stop offset="67%" stop-color="#3aae78"/>' +
+        '<stop offset="68%" stop-color="#40b274"/>' +
+        '<stop offset="69%" stop-color="#47b671"/>' +
+        '<stop offset="70%" stop-color="#4dba6d"/>' +
+        '<stop offset="71%" stop-color="#53be69"/>' +
+        '<stop offset="72%" stop-color="#59c265"/>' +
+        '<stop offset="73%" stop-color="#5fc661"/>' +
+        '<stop offset="74%" stop-color="#65ca5d"/>' +
+        '<stop offset="75%" stop-color="#6cce5a"/>' +
+        '<stop offset="76%" stop-color="#71cf56"/>' +
+        '<stop offset="77%" stop-color="#77d052"/>' +
+        '<stop offset="78%" stop-color="#7dd14e"/>' +
+        '<stop offset="79%" stop-color="#83d34a"/>' +
+        '<stop offset="80%" stop-color="#89d447"/>' +
+        '<stop offset="81%" stop-color="#8fd543"/>' +
+        '<stop offset="82%" stop-color="#95d63f"/>' +
+        '<stop offset="83%" stop-color="#9bd83b"/>' +
+        '<stop offset="84%" stop-color="#a1d938"/>' +
+        '<stop offset="85%" stop-color="#a7da34"/>' +
+        '<stop offset="86%" stop-color="#addc30"/>' +
+        '<stop offset="87%" stop-color="#b3dd2c"/>' +
+        '<stop offset="88%" stop-color="#b8de2a"/>' +
+        '<stop offset="89%" stop-color="#bedf2a"/>' +
+        '<stop offset="90%" stop-color="#c4e029"/>' +
+        '<stop offset="91%" stop-color="#cae029"/>' +
+        '<stop offset="92%" stop-color="#cfe128"/>' +
+        '<stop offset="93%" stop-color="#d5e228"/>' +
+        '<stop offset="94%" stop-color="#dbe327"/>' +
+        '<stop offset="95%" stop-color="#e1e427"/>' +
+        '<stop offset="96%" stop-color="#e6e426"/>' +
+        '<stop offset="97%" stop-color="#ece526"/>' +
+        '<stop offset="98%" stop-color="#f2e625"/>' +
+        '<stop offset="99%" stop-color="#f8e725"/></linearGradient></defs>' +
+        '<rect id="gradientRect" width="20" height="95%" ' +
+        'fill="url(#Gradient)"/><text x="25" y="12px" ' +
+        'font-family="sans-serif" font-size="12px" text-anchor="start">4' +
+        '</text><text x="25" y="50%" font-family="sans-serif" ' +
+        'font-size="12px" text-anchor="start">2</text><text x="25" y="95%" ' +
+        'font-family="sans-serif" font-size="12px" text-anchor="start">0</text>'
+      ]);
+    });
+
+    test('Test getInterpolatedColors', function() {
+      var five = ['0', '1', '2', '3', '4'];
+      var color = ColorViewController.getInterpolatedColors(five, 'Viridis');
+      deepEqual(color, { '0': '#440154', '1':
+        '#424c79', '2': '#30758c', '3': '#398f8b', '4': '#8cb373' });
+    });
+
+    test('Test ColorViewController.getScaledColors exceptions', function() {
+      var five = ['0', 'string1', 'string2', 'string3', 'string4'];
+
+      throws(
+          function() {
+            var color = ColorViewController.getScaledColors(five, 'Viridis');
+          },
+          Error,
+          'An error is raised if there are not 2+ numeric values'
+          );
+    });
+
+    test('Test ColorViewController.getColorList works', function() {
+      var one, five, ten, twenty, scaled, colors;
+
+      one = [0];
+      five = [0, 1, 2, 3, 4];
+      ten = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+      twenty = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+                18, 19];
+      scaled = [0, 1, 2, 3, 7, 20, 50];
+
+      colors = ColorViewController.getColorList(scaled, 'Blues', false, true);
+      deepEqual(colors[0], {'0': '#f7fbff', '1': '#f3f8fd', '2': '#eff5fc',
+                            '20': '#93c4de', '3': '#ebf3fb', '50': '#08306b',
+                            '7': '#dbe9f6'});
+      equal(colors[1], '<defs><linearGradient id=\"Gradient\" ' +
+        'x1=\"0\" x2=\"0\" y1=\"1\" y2=\"0\">' +
+        '<stop offset=\"0%\" stop-color=\"#f7fbff\"/>' +
+        '<stop offset=\"1%\" stop-color=\"#f5f9fe\"/>' +
+        '<stop offset=\"2%\" stop-color=\"#f3f8fd\"/>' +
+        '<stop offset=\"3%\" stop-color=\"#f1f7fd\"/>' +
+        '<stop offset=\"4%\" stop-color=\"#eff5fc\"/>' +
+        '<stop offset=\"5%\" stop-color=\"#edf4fb\"/>' +
+        '<stop offset=\"6%\" stop-color=\"#ebf3fb\"/>' +
+        '<stop offset=\"7%\" stop-color=\"#e9f2fa\"/>' +
+        '<stop offset=\"8%\" stop-color=\"#e7f0f9\"/>' +
+        '<stop offset=\"9%\" stop-color=\"#e5eff9\"/>' +
+        '<stop offset=\"10%\" stop-color=\"#e3eef8\"/>' +
+        '<stop offset=\"11%\" stop-color=\"#e1ecf7\"/>' +
+        '<stop offset=\"12%\" stop-color=\"#dfebf7\"/>' +
+        '<stop offset=\"13%\" stop-color=\"#ddeaf6\"/>' +
+        '<stop offset=\"14%\" stop-color=\"#dbe9f6\"/>' +
+        '<stop offset=\"15%\" stop-color=\"#d9e7f5\"/>' +
+        '<stop offset=\"16%\" stop-color=\"#d7e6f4\"/>' +
+        '<stop offset=\"17%\" stop-color=\"#d5e5f4\"/>' +
+        '<stop offset=\"18%\" stop-color=\"#d3e3f3\"/>' +
+        '<stop offset=\"19%\" stop-color=\"#d1e2f2\"/>' +
+        '<stop offset=\"20%\" stop-color=\"#cfe1f2\"/>' +
+        '<stop offset=\"21%\" stop-color=\"#cde0f1\"/>' +
+        '<stop offset=\"22%\" stop-color=\"#cbdef0\"/>' +
+        '<stop offset=\"23%\" stop-color=\"#c9ddf0\"/>' +
+        '<stop offset=\"24%\" stop-color=\"#c7dcef\"/>' +
+        '<stop offset=\"25%\" stop-color=\"#c6dbef\"/>' +
+        '<stop offset=\"26%\" stop-color=\"#c2d9ed\"/>' +
+        '<stop offset=\"27%\" stop-color=\"#bfd8ec\"/>' +
+        '<stop offset=\"28%\" stop-color=\"#bcd6eb\"/>' +
+        '<stop offset=\"29%\" stop-color=\"#b9d5ea\"/>' +
+        '<stop offset=\"30%\" stop-color=\"#b6d4e9\"/>' +
+        '<stop offset=\"31%\" stop-color=\"#b2d2e8\"/>' +
+        '<stop offset=\"32%\" stop-color=\"#afd1e7\"/>' +
+        '<stop offset=\"33%\" stop-color=\"#acd0e6\"/>' +
+        '<stop offset=\"34%\" stop-color=\"#a9cee4\"/>' +
+        '<stop offset=\"35%\" stop-color=\"#a6cde3\"/>' +
+        '<stop offset=\"36%\" stop-color=\"#a2cce2\"/>' +
+        '<stop offset=\"37%\" stop-color=\"#9fcae1\"/>' +
+        '<stop offset=\"38%\" stop-color=\"#9bc8e0\"/>' +
+        '<stop offset=\"39%\" stop-color=\"#97c6df\"/>' +
+        '<stop offset=\"40%\" stop-color=\"#93c4de\"/>' +
+        '<stop offset=\"41%\" stop-color=\"#8fc2dd\"/>' +
+        '<stop offset=\"42%\" stop-color=\"#8bbfdd\"/>' +
+        '<stop offset=\"43%\" stop-color=\"#87bddc\"/>' +
+        '<stop offset=\"44%\" stop-color=\"#83bbdb\"/>' +
+        '<stop offset=\"45%\" stop-color=\"#7fb9da\"/>' +
+        '<stop offset=\"46%\" stop-color=\"#7bb6d9\"/>' +
+        '<stop offset=\"47%\" stop-color=\"#77b4d8\"/>' +
+        '<stop offset=\"48%\" stop-color=\"#73b2d7\"/>' +
+        '<stop offset=\"49%\" stop-color=\"#6fb0d6\"/>' +
+        '<stop offset=\"50%\" stop-color=\"#6baed6\"/>' +
+        '<stop offset=\"51%\" stop-color=\"#67abd4\"/>' +
+        '<stop offset=\"52%\" stop-color=\"#64a9d3\"/>' +
+        '<stop offset=\"53%\" stop-color=\"#61a7d2\"/>' +
+        '<stop offset=\"54%\" stop-color=\"#5da5d0\"/>' +
+        '<stop offset=\"55%\" stop-color=\"#5aa2cf\"/>' +
+        '<stop offset=\"56%\" stop-color=\"#57a0ce\"/>' +
+        '<stop offset=\"57%\" stop-color=\"#549ecd\"/>' +
+        '<stop offset=\"58%\" stop-color=\"#509ccb\"/>' +
+        '<stop offset=\"59%\" stop-color=\"#4d99ca\"/>' +
+        '<stop offset=\"60%\" stop-color=\"#4a97c9\"/>' +
+        '<stop offset=\"61%\" stop-color=\"#4695c7\"/>' +
+        '<stop offset=\"62%\" stop-color=\"#4393c6\"/>' +
+        '<stop offset=\"63%\" stop-color=\"#4090c5\"/>' +
+        '<stop offset=\"64%\" stop-color=\"#3e8ec3\"/>' +
+        '<stop offset=\"65%\" stop-color=\"#3b8bc2\"/>' +
+        '<stop offset=\"66%\" stop-color=\"#3888c1\"/>' +
+        '<stop offset=\"67%\" stop-color=\"#3686bf\"/>' +
+        '<stop offset=\"68%\" stop-color=\"#3383be\"/>' +
+        '<stop offset=\"69%\" stop-color=\"#3080bd\"/>' +
+        '<stop offset=\"70%\" stop-color=\"#2e7ebb\"/>' +
+        '<stop offset=\"71%\" stop-color=\"#2b7bba\"/>' +
+        '<stop offset=\"72%\" stop-color=\"#2878b9\"/>' +
+        '<stop offset=\"73%\" stop-color=\"#2676b7\"/>' +
+        '<stop offset=\"74%\" stop-color=\"#2373b6\"/>' +
+        '<stop offset=\"75%\" stop-color=\"#2171b5\"/>' +
+        '<stop offset=\"76%\" stop-color=\"#1f6eb3\"/>' +
+        '<stop offset=\"77%\" stop-color=\"#1c6bb1\"/>' +
+        '<stop offset=\"78%\" stop-color=\"#1a69af\"/>' +
+        '<stop offset=\"79%\" stop-color=\"#1866ad\"/>' +
+        '<stop offset=\"80%\" stop-color=\"#1664ab\"/>' +
+        '<stop offset=\"81%\" stop-color=\"#1461a9\"/>' +
+        '<stop offset=\"82%\" stop-color=\"#135fa7\"/>' +
+        '<stop offset=\"83%\" stop-color=\"#115ca5\"/>' +
+        '<stop offset=\"84%\" stop-color=\"#0f59a3\"/>' +
+        '<stop offset=\"85%\" stop-color=\"#0d57a1\"/>' +
+        '<stop offset=\"86%\" stop-color=\"#0b549f\"/>' +
+        '<stop offset=\"87%\" stop-color=\"#09529d\"/>' +
+        '<stop offset=\"88%\" stop-color=\"#084f9a\"/>' +
+        '<stop offset=\"89%\" stop-color=\"#084d96\"/>' +
+        '<stop offset=\"90%\" stop-color=\"#084a92\"/>' +
+        '<stop offset=\"91%\" stop-color=\"#08478e\"/>' +
+        '<stop offset=\"92%\" stop-color=\"#08458a\"/>' +
+        '<stop offset=\"93%\" stop-color=\"#084286\"/>' +
+        '<stop offset=\"94%\" stop-color=\"#083f82\"/>' +
+        '<stop offset=\"95%\" stop-color=\"#083d7e\"/>' +
+        '<stop offset=\"96%\" stop-color=\"#083a7a\"/>' +
+        '<stop offset=\"97%\" stop-color=\"#083776\"/>' +
+        '<stop offset=\"98%\" stop-color=\"#083572\"/>' +
+        '<stop offset=\"99%\" stop-color=\"#08326e\"/>' +
+        '<stop offset=\"100%\" stop-color=\"#08306b\"/>' +
+        '</linearGradient></defs><rect id=\"gradientRect\" width=\"20\" ' +
+        'height=\"95%\" fill=\"url(#Gradient)\"/><text x=\"25\" y=\"12px\" ' +
+        'font-family=\"sans-serif\" font-size=\"12px\" text-anchor=\"start\">' +
+        '50</text><text x=\"25\" y=\"50%\" font-family=\"sans-serif\" ' +
+        'font-size=\"12px\" text-anchor=\"start\">25</text><text x=\"25\" ' +
+        'y=\"95%\" font-family=\"sans-serif\" font-size=\"12px\" ' +
+        'text-anchor=\"start\">0</text>');
+
+      deepEqual(ColorViewController.getColorList(five, 'Set1', true),
+                [{'0': '#e41a1c', '1': '#377eb8', '2': '#4daf4a',
+                  '3': '#984ea3', '4': '#ff7f00'}, undefined]);
+
+      deepEqual(ColorViewController.getColorList(twenty, 'BrBG', false),
+                [{'0': '#543005', '1': '#6e4a1c', '2': '#866231',
+                  '3': '#9c7a46', '4': '#b0905a', '5': '#c1a46e',
+                  '6': '#d1b681', '7': '#dec693', '8': '#e9d4a4',
+                  '9': '#f1dfb4', '10': '#f6e8c3', '11': '#f4e9cb',
+                  '12': '#efe9d1', '13': '#e6e6d3', '14': '#dae1d2',
+                  '15': '#c9dace', '16': '#b6d1c7', '17': '#9ec6bd',
+                  '18': '#82b8b1', '19': '#61a9a1'}, undefined]);
+
+      deepEqual(ColorViewController.getColorList(one, 'OrRd', false),
+                [{'0': '#fff7ec'}, undefined]);
+      deepEqual(ColorViewController.getColorList(one, 'RdGy', true),
+                [{'0': '#67001f'}, undefined]);
+
+    });
+
+    test('Test ColorViewController.getColorList exceptions', function() {
+      var five;
+      five = [0, 1, 2, 3, 4];
+      throws(
+          function() {
+            ColorViewController.getColorList(five, false, 'Non-existant');
+          },
+          Error,
+          'An error is raised if the colormap does not exist'
+          );
+
+      five = [0, 'string1', 'string2', 'string3', 'string4'];
+      throws(
+          function() {
+            ColorViewController.getColorList(five, 'Blues', false, true);
+          },
+          Error,
+          'Error is raised if there are less than 2 numeric values when scaled'
+          );
+    });
+
+    test('Testing setPlottableAttributes helper function', function(assert) {
+      // testing with one plottable
+      var idx = 0;
+      plottables = [{idx: idx}];
+      equal(this.dv.markers[idx].material.color.getHexString(), 'ff0000');
+      equal(this.dv.markers[idx + 1].material.color.getHexString(), 'ff0000');
+      ColorViewController.prototype.setPlottableAttributes(this.dv, '#00ff00',
+                                                           plottables);
+      equal(this.dv.markers[idx].material.color.getHexString(), '00ff00');
+      equal(this.dv.markers[idx + 1].material.color.getHexString(), 'ff0000');
+      equal(this.dv.needsUpdate, true);
+
+      // testing with multiple plottable
+      plottables = [{idx: idx}, {idx: idx + 1}];
+      ColorViewController.prototype.setPlottableAttributes(this.dv, '#000000',
+                                                           plottables);
+      equal(this.dv.markers[idx].material.color.getHexString(), '000000');
+      equal(this.dv.markers[idx + 1].material.color.getHexString(), '000000');
+      equal(this.dv.needsUpdate, true);
+    });
+
+    test('Testing toJSON', function() {
+      var container = $('<div style="height:11px; width:12px"></div>');
+      var controller = new ColorViewController(
+        container, this.sharedDecompositionViewDict);
+      // Change color on one point
+      var idx = 0;
+      plottables = [{idx: idx}];
+      ColorViewController.prototype.setPlottableAttributes(this.dv, '#00ff00',
+                                                           plottables);
+
+      var obs = controller.toJSON();
+      var exp = {category: 'SampleID',
+                 colormap: 'discrete-coloring-qiime',
+                 continuous: false,
+                 data: {'PC.636': '#ff0000', 'PC.635': '#0000ff',
+                        'PC.634': '#f27304'}};
+      deepEqual(obs, exp);
+    });
+
+    test('Testing fromJSON', function() {
+      var json = {category: 'DOB',
+                  colormap: 'discrete-coloring-qiime',
+                  continuous: false,
+                  data: {20070314: '#ff0000', 20071112: '#0000ff'}};
+
+      var container = $('<div style="height:11px; width:12px"></div>');
+      var controller = new ColorViewController(
+        container, this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+      var idx = 0;
+      var markers = controller.decompViewDict.scatter.markers;
+      equal(markers[idx].material.color.getHexString(), 'ff0000');
+      equal(markers[idx + 1].material.color.getHexString(), '0000ff');
+      equal(markers[idx + 2].material.color.getHexString(), '0000ff');
+      equal(controller.$select.val(), 'DOB');
+      equal(controller.$colormapSelect.val(), 'discrete-coloring-qiime');
+      equal(controller.$scaled.is(':checked'), false);
+    });
+
+    test('Testing fromJSON scaled', function() {
+      var json = {category: 'Mixed', colormap: 'Viridis',
+                  continuous: true, data: {'Non-numeric values': '#ae1221'}};
+
+      var container = $('<div style="height:11px; width:12px"></div>');
+      var controller = new ColorViewController(
+        container, this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+      var idx = 0;
+      var markers = controller.decompViewDict.scatter.markers;
+      equal(markers[idx].material.color.getHexString(), '440154');
+      equal(markers[idx + 1].material.color.getHexString(), 'ae1221');
+      equal(markers[idx + 2].material.color.getHexString(), 'fee825');
+      equal(controller.$select.val(), 'Mixed');
+      equal(controller.$colormapSelect.val(), 'Viridis');
+      equal(controller.$scaled.is(':checked'), true);
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_decomposition_model.js b/tests/javascript_tests/test_decomposition_model.js
new file mode 100644
index 0000000..3f41b29
--- /dev/null
+++ b/tests/javascript_tests/test_decomposition_model.js
@@ -0,0 +1,633 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model'
+], function($, _, model) {
+
+  $(document).ready(function() {
+    var DecompositionModel = model.DecompositionModel;
+    var Plottable = model.Plottable;
+
+    // these variables are reused throughout this test suite
+    var name, ids, coords, pct_var, md_headers, metadata;
+
+    module('Decomposition Model', {
+      setup: function() {
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593',
+        'PC.355', 'PC.607', 'PC.634'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794],
+          [0.228820, -0.130142, -0.287149, 0.086450, 0.044295, 0.206043,
+          0.031000, 0.071992],
+          [0.042263, -0.013968, 0.063531, -0.346121, -0.127814, 0.013935,
+          0.030021, 0.140148],
+          [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+          -0.035430, -0.255786],
+          [0.232873, 0.139788, 0.322871, 0.183347, 0.020466, 0.054059,
+          -0.036625, 0.099824],
+          [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+          0.057609, 0.024248],
+          [-0.091330, 0.424147, -0.135627, -0.057519, 0.151363, -0.025394,
+          0.051731, -0.038738],
+          [-0.349339, -0.120788, 0.115275, 0.069495, -0.025372, 0.067853,
+          0.244448, -0.059883]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+        metadata = [['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+        ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+        ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+        ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+        ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+        ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+        ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+        ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126']];
+      },
+      teardown: function() {
+        // teardown function
+        name = null;
+        ids = null;
+        coords = null;
+        pct_var = null;
+        md_headers = null;
+        metadata = null;
+      }
+    });
+
+    /**
+     *
+     * Test that the Decomposition model object can be constructed without any
+     * problems and check that the attributes are set correctly
+     *
+     */
+    test('Test constructor', function() {
+
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+      equal(dm.abbreviatedName, 'pcoa', 'Abbreviated name set correctly');
+
+      var exp = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+      10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+      deepEqual(dm.percExpl, exp, 'Percentage explained set correctly');
+
+      exp = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+      deepEqual(dm.md_headers, exp, 'Metadata headers set correctly');
+
+      exp = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593',
+      'PC.355', 'PC.607', 'PC.634'];
+      deepEqual(dm.ids, exp, 'Ids set correctly');
+
+      exp = [
+        new Plottable(
+            'PC.636',
+            ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+            [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+            -0.229889, -0.046599],
+            0),
+        new Plottable(
+            'PC.635',
+            ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+            [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+            -0.112864, 0.064794],
+            1),
+        new Plottable(
+            'PC.356',
+            ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+            [0.228820, -0.130142, -0.287149, 0.086450, 0.044295, 0.206043,
+            0.031000, 0.071992],
+            2),
+        new Plottable(
+            'PC.481',
+            ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+            [0.042263, -0.013968, 0.063531, -0.346121, -0.127814, 0.013935,
+            0.030021, 0.140148],
+            3),
+        new Plottable(
+            'PC.354',
+            ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+            [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+            -0.035430, -0.255786],
+            4),
+        new Plottable(
+            'PC.593',
+            ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+            [0.232873, 0.139788, 0.322871, 0.183347, 0.020466, 0.054059,
+            -0.036625, 0.099824],
+            5),
+        new Plottable(
+            'PC.355',
+            ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+            [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+            0.057609, 0.024248],
+            6),
+        new Plottable(
+            'PC.607',
+            ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+            [-0.091330, 0.424147, -0.135627, -0.057519, 0.151363, -0.025394,
+            0.051731, -0.038738],
+            7),
+        new Plottable(
+            'PC.634',
+            ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126'],
+            [-0.349339, -0.120788, 0.115275, 0.069495, -0.025372, 0.067853,
+            0.244448, -0.059883],
+            8)];
+      deepEqual(dm.plottable, exp, 'Plottables set correctly');
+
+      deepEqual(dm.dimensionRanges.min, [-0.349339, -0.194113, -0.287149,
+                                         -0.346121, -0.247485, -0.279924,
+                                         -0.229889, -0.255786]);
+      deepEqual(dm.dimensionRanges.max, [0.280399, 0.424147, 0.322871,
+                                         0.183347, 0.17607, 0.206043, 0.244448,
+                                         0.140148]);
+
+      equal(dm.length, 9, 'Length set correctly');
+      deepEqual(dm.axesNames, []);
+    });
+
+    /**
+     *
+     * Test constructor with custom axesNames
+     *
+     */
+    test('Test axesNames', function() {
+      var names = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata, names);
+      deepEqual(dm.axesNames, names, 'Plottable retrieved successfully');
+    });
+
+    /**
+     *
+     * Test the initializer raises an error if the number of rows in coords is
+     * not the same as the number of ids
+     *
+     */
+    test('Test constructor excepts num rows coord != num ids', function() {
+      var result;
+
+      throws(
+          function() {
+            err_coords = [
+              [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+              -0.229889, -0.046599],
+              [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+              -0.112864, 0.064794],
+              [0.228820, -0.130142, -0.287149, 0.086450, 0.044295, 0.206043,
+              0.031000, 0.071992],
+              [0.042263, -0.013968, 0.063531, -0.346121, -0.127814, 0.013935,
+              0.030021, 0.140148],
+              [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+              -0.035430, -0.255786],
+              [0.232873, 0.139788, 0.322871, 0.183347, 0.020466, 0.054059,
+              -0.036625, 0.099824],
+              [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+              0.057609, 0.024248]];
+            result = new DecompositionModel(name, ids, err_coords, pct_var,
+                md_headers, metadata);
+          },
+          Error,
+          'An error is raised if the number of rows in the coords parameter ' +
+            'does not correspond to the number of ids'
+            );
+    });
+
+    /**
+     *
+     * Test the initializer raises an error if all rows in coords does not have
+     * the same number of elements
+     *
+     */
+    test('Test constructor excepts rows in coord different lengths',
+         function() {
+      var result;
+
+      throws(
+          function() {
+            err_coords = [
+              [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+              -0.229889, -0.046599],
+              [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+              -0.112864, 0.064794],
+              [0.228820, -0.130142, -0.287149, 0.086450, 0.044295, 0.206043,
+              0.031000, 0.071992],
+              [0.042263, -0.013968, 0.063531, -0.346121, -0.127814, 0.013935,
+              0.030021, 0.140148],
+              [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+              -0.035430, -0.255786],
+              [0.232873, 0.139788, 0.322871, 0.183347, 0.020466, 0.054059,
+              -0.036625, 0.099824],
+              [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+              0.057609, 0.024248],
+              [-0.091330, 0.424147, -0.135627, -0.057519, 0.151363, -0.025394,
+              0.051731, -0.038738],
+              [-0.349339, -0.120788]];
+            result = new DecompositionModel(name, ids, err_coords, pct_var,
+                md_headers, metadata);
+          },
+      Error,
+      'An error is raised if all rows in coords does not have the same length'
+        );
+    });
+
+    /**
+     *
+     * Test the initializer raises an error if the number of elements in
+     * pct_var does not correspond to the number of coords.
+     *
+     */
+    test('Test constructor excepts num pct_var != num coords', function() {
+      var result;
+      throws(
+          function() {
+            err_pct_var = [26.6887048633, 16.2563704022, 13.7754129161,
+            11.217215823, 10.024774995, 8.22835130237];
+            result = new DecompositionModel(name, ids, coords, err_pct_var,
+                md_headers, metadata);
+          },
+          Error,
+          'An error is raised if the number of percentage explained does not ' +
+          'correspond to the number of coords'
+          );
+    });
+
+    /**
+     *
+     * Test the initializer raises an error if the number of rows in metadata
+     * is not the same as the number of ids
+     *
+     */
+    test('Test constructor excepts num rows metadata != num ids', function() {
+      var result;
+
+      throws(
+          function() {
+            err_metadata = [
+              ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+              ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+              ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+              ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116']];
+            result = new DecompositionModel(name, ids, coords, pct_var,
+                md_headers, err_metadata);
+          },
+          Error,
+          'An error is raised if the number of rows in the metadata parameter' +
+          ' does not correspond to the number of ids'
+          );
+    });
+
+    /**
+     *
+     * Test the initializer raises an error if the number of columns in metadata
+     * is not the same as the number of metadata headers
+     *
+     */
+    test('Test constructor excepts metadata cols != num headers', function() {
+      var result;
+
+      throws(
+          function() {
+            err_metadata = [
+              ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+              ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+              ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+              ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+              ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+              ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', '20080116'],
+              ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+              ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+              ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126']];
+            result = new DecompositionModel(name, ids, coords, pct_var,
+                md_headers, err_metadata);
+          },
+          Error,
+          'An error is raised if the number of elements in each row in the ' +
+          'metadata parameter does not match the number of metadata columns'
+          );
+    });
+
+    /**
+     *
+     * Test getPlottableByID returns the correct plottable object
+     *
+     */
+    test('Test getPlottableByID', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+
+      var obs = dm.getPlottableByID('PC.636');
+      var exp = new Plottable(
+          'PC.636',
+          ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          0);
+
+      deepEqual(obs, exp, 'Plottable retrieved successfully');
+
+    });
+
+    /**
+     *
+     * Test getPlottableByID throws an error if the id does not exist in the
+     * DecompositionModel object
+     *
+     */
+    test('Test getPlottableByID excepts unrecognized id', function() {
+      var result;
+      throws(
+          function() {
+            var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                            md_headers, metadata);
+            result = dm.getPlottableByID('Does_not_exist');
+          },
+          Error,
+          'An error is raised if the id is not present in the Decomposition ' +
+          'Model object'
+          );
+    });
+
+    /**
+     *
+     * Test getPlottableByIDs returns the correct list of plottables
+     *
+     */
+    test('Test getPlottableByIDs', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+
+      var obs = dm.getPlottableByIDs(['PC.636', 'PC.354', 'PC.355']);
+      var exp = [
+        new Plottable(
+            'PC.636',
+            ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+            [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+            -0.229889, -0.046599],
+            0),
+        new Plottable(
+            'PC.354',
+            ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+            [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+            -0.035430, -0.255786],
+            4),
+        new Plottable(
+            'PC.355',
+            ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+            [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+            0.057609, 0.024248],
+            6)];
+
+      deepEqual(obs, exp, 'Plottable list retrieved successfully');
+    });
+
+    /**
+     *
+     * Test getPlottableByIDs throws an error if a passed id does not exist in
+     * the DecompositionModel object
+     *
+     */
+
+    test('Test getPlottableByIDs excepts unrecognized id', function() {
+      var result;
+      throws(
+          function() {
+            var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                            md_headers, metadata);
+            result = dm.getPlottableByIDs(['PC.636', 'PC.354',
+                                           'Does_not_exist']);
+          },
+          Error,
+          'An error is raised if one of the ids is not present in the ' +
+          'Decomposition Model object'
+          );
+    });
+
+    /**
+     *
+     * Test _getMetadataIndex returns the correct index of a category
+     *
+     */
+    test('Test _getMetadataIndex', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+      equal(dm._getMetadataIndex('Treatment'), 2,
+          'Header index retrieved successfully');
+    });
+
+    /**
+     *
+     * Test _getMetadataIndex throws an error if the passed columns does not
+     * exists in the DecompositionModel
+     *
+     */
+    test('Test _getMetadataIndex excepts unrecognized header', function() {
+      var result;
+      throws(
+          function() {
+            var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                            md_headers, metadata);
+            result = dm._getMetadataIndex('Does_not_exist');
+          },
+          Error,
+          'An error is raised if the metadata header does not exist in the ' +
+          'Decomposition Model object'
+          );
+    });
+
+    /**
+     *
+     * Test getPlottablesByMetadataCategoryValue retrieves all the plottables
+     * with the metadata category value associated.
+     *
+     */
+    test('Test getPlottablesByMetadataCategoryValue', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+      var obs = dm.getPlottablesByMetadataCategoryValue('Treatment',
+                                                        'Control');
+      var exp = [
+        new Plottable(
+            'PC.636',
+            ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+            [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+            -0.229889, -0.046599],
+            0),
+        new Plottable(
+            'PC.354',
+            ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+            [0.280399, -0.006013, 0.023485, -0.046811, -0.146624, 0.005670,
+            -0.035430, -0.255786],
+            4),
+        new Plottable(
+            'PC.355',
+            ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+            [0.170518, -0.194113, -0.030897, 0.019809, 0.155100, -0.279924,
+            0.057609, 0.024248],
+            6),
+        new Plottable(
+            'PC.607',
+            ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+            [-0.091330, 0.424147, -0.135627, -0.057519, 0.151363, -0.025394,
+            0.051731, -0.038738],
+            7),
+        new Plottable(
+            'PC.634',
+            ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126'],
+            [-0.349339, -0.120788, 0.115275, 0.069495, -0.025372, 0.067853,
+            0.244448, -0.059883],
+            8)];
+
+      deepEqual(obs, exp,
+          'Plottables for the given metadata category value retrieved ' +
+          'successfully');
+    });
+
+    /**
+     *
+     * Test getPlottablesByMetadataCategoryValue throws an error if the
+     * metadata header does not exist in the Decomposition Model object.
+     *
+     */
+    test('Test getPlottablesByMetadataCategoryValue excepts unrecognized ' +
+        'header', function() {
+          var result;
+          throws(
+              function() {
+                var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                                md_headers, metadata);
+                result = dm.getPlottablesByMetadataCategoryValue('foo',
+                                                                 'Control');
+              },
+              Error,
+              'An error is raised if the metadata header does not exist in ' +
+              'the Decomposition Model object'
+              );
+        });
+
+    /**
+     *
+     * Test getPlottablesByMetadataCategoryValue throws an error if the metadata
+     * values is not found in the given category
+     *
+     */
+    test('Tests getPlottablesByMetadataCategoryValue excepts unrecognized ' +
+        'metadata category value', function() {
+          var result;
+          throws(
+              function() {
+                var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                                md_headers, metadata);
+                result = dm.getPlottablesByMetadataCategoryValue('Treatment',
+                                                                 'foo');
+              },
+              Error,
+              'An error is raised if the metadata category value does not ' +
+              'exist in the Decomposition Model object'
+              );
+        });
+
+    /**
+     *
+     * Test the function used to find minimum and maximum values works.
+     *
+     */
+    test('Test the _minMaxReduce function', function() {
+        var p = new Plottable('PC.635', ['PC.635', 'YATGCTGCCTCCCGTAGGAGT',
+                              'Fast', '20071112'], [-0.237661, 0.046053,
+                              -0.138136, 0.159061, -0.247485, -0.115211,
+                              -0.112864, 0.064794], 1);
+        var accumulator = {'min': [-5, -5, -5, -5, -5, -6, -0.01, -8],
+                           'max': [0, 0, 0, 0, 0, 0, 0, 0]};
+
+        var val = DecompositionModel._minMaxReduce(accumulator, p);
+
+        deepEqual(val.min, [-5, -5, -5, -5, -5, -6, -0.112864, -8]);
+        deepEqual(val.max, [0, 0.046053, 0, 0.159061, 0, 0, 0, 0.064794]);
+    });
+
+    /**
+     *
+     * Tests if a unique set of metadata category values can be obtained from a
+     * metadata category
+     *
+     */
+    test('Test getUniqueValuesByCategory', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+      var obs = dm.getUniqueValuesByCategory('Treatment').sort();
+      var exp = ['Control', 'Fast'];
+
+      deepEqual(obs, exp, 'Unique metadata values retrieved successfully');
+    });
+
+    /**
+     *
+     * Tests getUniqueValuesByCategory throws an error if the metadata header
+     * does not exists
+     *
+     */
+    test('Test getUniqueValuesByCategory excepts unrecognized headers',
+        function() {
+          var result;
+          throws(
+              function() {
+                var dm = new DecompositionModel(name, ids, coords, pct_var,
+                                                md_headers, metadata);
+                result = dm.getUniqueValuesByCategory('Does_not_exist');
+              },
+              Error,
+              'An error is raised if the metadata category value does not ' +
+              'exist in the Decomposition Model object'
+              );
+        });
+
+    /**
+     *
+     * Tests apply executes the provided function for all the plottables
+     * in the decomposition object
+     *
+     */
+    test('Test apply', function() {
+      var dm = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+          metadata);
+      var obs = dm.apply(function(pl) {return pl.name});
+      var exp = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593',
+      'PC.355', 'PC.607', 'PC.634'];
+      deepEqual(obs, exp, 'Apply works as expected');
+    });
+
+    /**
+     *
+     * Tests the toString method
+     *
+     */
+    test('Test toString', function() {
+      var _ids = ['samp1', 'samp2'];
+      var _coords = [[1, 2, 3], [4, 5, 6]];
+      var _pct_var = [0.5, 0.4, 0.1];
+      var _md_headers = ['foo1', 'foo2', 'foo3'];
+      var _metadata = [['a', 'b', 'c'], ['d', 'f', 'g']];
+      var dm = new DecompositionModel(name, _ids, _coords, _pct_var,
+                                      _md_headers, _metadata);
+      var exp = 'name: pcoa\n' +
+        'Metadata headers: [foo1, foo2, foo3]\n' +
+        'Plottables:\n' +
+        'Sample: samp1 located at: (1, 2, 3) ' +
+        'metadata: [a, b, c] at index: 0 and without confidence intervals.\n' +
+        'Sample: samp2 located at: (4, 5, 6) ' +
+        'metadata: [d, f, g] at index: 1 and without confidence intervals.';
+
+      equal(dm.toString(), exp,
+          'Test correctly converted DecompositionModel to string type');
+
+    });
+
+  });
+
+});
diff --git a/tests/javascript_tests/test_decomposition_view.js b/tests/javascript_tests/test_decomposition_view.js
new file mode 100644
index 0000000..215c736
--- /dev/null
+++ b/tests/javascript_tests/test_decomposition_view.js
@@ -0,0 +1,218 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view'
+], function($, _, model, DecompositionView) {
+  $(document).ready(function() {
+    var DecompositionModel = model.DecompositionModel;
+
+    module('Decomposition View', {
+      setup: function() {
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+        metadata = [['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+      },
+
+      teardown: function() {
+        // teardown function
+        name = null;
+        ids = null;
+        coords = null;
+        pct_var = null;
+        md_headers = null;
+        metadata = null;
+        decomp = null;
+      }
+    });
+
+    /**
+     *
+     * Test that the Decomposition View object is initialized correctly
+     *
+     */
+    test('Test constructor', function() {
+      var obs;
+      var dv = new DecompositionView(decomp);
+      var _name = 'pcoa';
+      var _ids = ['PC.636', 'PC.635'];
+      var _coords = [
+        [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+        -0.229889, -0.046599],
+        [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+        -0.112864, 0.064794]];
+      var _pct_var = [26.6887048633, 16.2563704022, 13.7754129161,
+                      11.217215823, 10.024774995, 8.22835130237, 7.55971173665,
+                      6.24945796136];
+      var _md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment',
+                         'DOB'];
+      var _metadata = [
+        ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']];
+      var exp = new DecompositionModel(_name, _ids, _coords, _pct_var,
+          _md_headers, _metadata);
+
+      deepEqual(dv.decomp, exp, 'decomp set correctly');
+      equal(dv.count, 2, 'count set correctly');
+      equal(dv.visibleCount, 2, 'visibleCount set correctly');
+      deepEqual(dv.visibleDimensions, [0, 1, 2],
+          'visibleDimensions set correctly');
+      deepEqual(dv.tubes, [], 'tubes set correctly');
+
+      equal(dv.axesColor, 0xFFFFFF);
+      equal(dv.backgroundColor, 0x000000);
+
+      deepEqual(dv.axesOrientation, [1, 1, 1]);
+
+      /*
+         I'm unsure on how to test this, so right now just testing what I think
+         makes sense to test
+       */
+      obs = [dv.markers[0].position.x,
+      dv.markers[0].position.y,
+      dv.markers[0].position.z];
+      exp = [-0.276542, -0.144964, 0.066647];
+      deepEqual(obs, exp, 'First marker position set correctly');
+      obs = [dv.markers[1].position.x,
+      dv.markers[1].position.y,
+      dv.markers[1].position.z];
+      exp = [-0.237661, 0.046053, -0.138136];
+      deepEqual(obs, exp, 'Second marker position set correctly');
+      deepEqual(dv.lines, [], 'lines set correctly');
+      /*
+         TODO: How do we test this?
+         */
+      // deepEqual(dv._genericSphere, undefined,
+      //           "_genericSphere set correctly");
+    });
+
+    /**
+     *
+     * Test that changeVisibleDimensions updates the meshes position
+     *
+     */
+    test('Test changeVisibleDimensions', function() {
+      var dv = new DecompositionView(decomp);
+      dv.changeVisibleDimensions([2, 3, 4]);
+      obs = [dv.markers[0].position.x,
+      dv.markers[0].position.y,
+      dv.markers[0].position.z];
+      exp = [0.066647, -0.067711, 0.176070];
+      deepEqual(obs, exp, 'First marker position updated correctly');
+      obs = [dv.markers[1].position.x,
+      dv.markers[1].position.y,
+      dv.markers[1].position.z];
+      exp = [-0.138136, 0.159061, -0.247485];
+      deepEqual(obs, exp, 'Second marker position updated correctly');
+
+      deepEqual(dv.axesOrientation, [1, 1, 1]);
+    });
+
+    /**
+     *
+     * Test the changeVisibleDimensions throws an error if the number of
+     * dimensions passes is different the 3
+     *
+     */
+    test('Test changeVisibleDimensions excepts', function() {
+      throws(
+          function() {
+            var dv = new DecompositionView(decomp);
+            dv.changeVisibleDimensions([2, 3, 4, 5]);
+          },
+          Error,
+          'An error is raised if the number of dimensions is not 3'
+          );
+    });
+
+    /**
+     *
+     * Test that changeVisibleDimensions updates the meshes position
+     *
+     */
+    test('Test change flip axes', function(assert) {
+      var dv = new DecompositionView(decomp);
+
+      // copy the arrays
+      expa = _.clone(dv.markers[0].position.toArray());
+      expb = _.clone(dv.markers[1].position.toArray());
+
+      // flip the orientation of the position
+      expb[1] = expb[1] * -1;
+      expa[1] = expa[1] * -1;
+
+      // change the position of the decomposition view and ...
+      dv.flipVisibleDimension(1);
+
+      // ... Check for the following things:
+      //
+      // 1.- The position themselves
+      // 2.- The ranges i.e. positions still fall within the dimensionRanges.
+      // 3.- The axis orientation vector
+      obs = dv.markers[0].position.toArray();
+      deepEqual(obs, expa, 'First marker position updated correctly');
+
+      assert.ok(obs[1] <= dv.decomp.dimensionRanges.max[1],
+                'Falls within range (max)');
+      assert.ok(obs[1] >= dv.decomp.dimensionRanges.min[1],
+                'Falls within range (min)');
+
+      obs = dv.markers[1].position.toArray();
+      deepEqual(obs, expb, 'Second marker position updated correctly');
+
+      assert.ok(obs[1] <= dv.decomp.dimensionRanges.max[1],
+                'Falls within range (max)');
+      assert.ok(obs[1] >= dv.decomp.dimensionRanges.min[1],
+                'Falls within range (min)');
+
+      deepEqual(dv.axesOrientation, [1, -1, 1]);
+    });
+
+    /**
+     *
+     * Test that changeVisibleDimensions and flip axis
+     *
+     */
+    test('Test changing the orientations and then flipping a dimension',
+         function() {
+      var dv = new DecompositionView(decomp);
+
+      deepEqual(dv.axesOrientation, [1, 1, 1]);
+
+      dv.changeVisibleDimensions([2, 3, 4]);
+      obs = dv.markers[0].position.toArray();
+      exp = [0.066647, -0.067711, 0.176070];
+      deepEqual(obs, exp, 'First marker position updated correctly');
+
+      obs = dv.markers[1].position.toArray();
+      exp = [-0.138136, 0.159061, -0.247485];
+      deepEqual(obs, exp, 'Second marker position updated correctly');
+
+      deepEqual(dv.axesOrientation, [1, 1, 1]);
+
+      dv.flipVisibleDimension(3);
+
+      obs = dv.markers[0].position.toArray();
+      exp = [0.066647, 0.067711, 0.176070];
+      deepEqual(obs, exp, 'First marker position updated correctly');
+
+      obs = dv.markers[1].position.toArray();
+      exp = [-0.138136, -0.159061, -0.247485];
+      deepEqual(obs, exp, 'Second marker position updated correctly');
+
+      deepEqual(dv.axesOrientation, [1, -1, 1]);
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_draw.js b/tests/javascript_tests/test_draw.js
new file mode 100644
index 0000000..005eb4b
--- /dev/null
+++ b/tests/javascript_tests/test_draw.js
@@ -0,0 +1,164 @@
+requirejs(['draw'], function(draw) {
+  var formatSVGLegend = draw.formatSVGLegend;
+  var makeLine = draw.makeLine;
+  var makeLabel = draw.makeLabel;
+  $(document).ready(function() {
+
+    module('Drawing utilities', {
+
+      setup: function() {
+      },
+
+      teardown: function() {
+      }
+
+    });
+
+    /**
+     *
+     * Test that makeLine works
+     *
+     */
+    test('Test makeLine works correctly', function(assert) {
+      var testLine = makeLine([0, 0, 0], [1, 1, 1], 0x00ff00, 1, true);
+
+      equal(testLine.material.opacity, 1.0);
+      equal(testLine.material.transparent, true);
+
+      equal(testLine.geometry.vertices[0].x, 0);
+      equal(testLine.geometry.vertices[0].y, 0);
+      equal(testLine.geometry.vertices[0].z, 0);
+
+      equal(testLine.geometry.vertices[1].x, 1);
+      equal(testLine.geometry.vertices[1].y, 1);
+      equal(testLine.geometry.vertices[1].z, 1);
+
+      equal(testLine.material.color.r, 0);
+      equal(testLine.material.color.g, 1);
+      equal(testLine.material.color.b, 0);
+
+      testLine = makeLine([0, 0, 0], [1, 1, 1], 0x00ff00, 1, false);
+
+      equal(testLine.material.opacity, 1.0);
+      equal(testLine.material.transparent, false);
+
+      equal(testLine.geometry.vertices[0].x, 0);
+      equal(testLine.geometry.vertices[0].y, 0);
+      equal(testLine.geometry.vertices[0].z, 0);
+
+      equal(testLine.geometry.vertices[1].x, 1);
+      equal(testLine.geometry.vertices[1].y, 1);
+      equal(testLine.geometry.vertices[1].z, 1);
+
+      equal(testLine.material.color.r, 0);
+      equal(testLine.material.color.g, 1);
+      equal(testLine.material.color.b, 0);
+    });
+
+    /**
+     *
+     * Test that makeLabel works correctly without a factor
+     *
+     */
+    test('Test makeLabel works correctly', function(assert) {
+      var label = makeLabel([0, 0, 0], 'foolibusters', 0x00FF00);
+
+      equal(label.material.color.r, 0);
+      equal(label.material.color.g, 1);
+      equal(label.material.color.b, 0);
+
+      equal(label.position.x, 0);
+      equal(label.position.y, 0);
+      equal(label.position.z, 0);
+
+      equal(label.text, 'foolibusters');
+    });
+
+    /**
+     *
+     * Test that makeLabel works correctly with a factor.
+     *
+     */
+    test('Test makeLabel works correctly', function(assert) {
+      var label = makeLabel([0, 0, 0], 'foolibusters', 0xFFFF00, 20);
+
+      equal(label.material.color.r, 1);
+      equal(label.material.color.g, 1);
+      equal(label.material.color.b, 0);
+
+      equal(label.position.x, 0);
+      equal(label.position.y, 0);
+      equal(label.position.z, 0);
+
+      equal(label.text, 'foolibusters');
+    });
+
+    /**
+     *
+     * Test that the SVG file is generated correctly.
+     *
+     */
+    test('Test formatSVGLegend works correctly', function() {
+      var res, names = [], colors = [], exp = '';
+
+      e = '<svg xmlns="http://www.w3.org/2000/svg" width="168" height="191">' +
+      '<g><rect height="27" width="27" y="1" x="5" style="stroke-width:1;str' +
+      'oke:rgb(0,0,0)" fill="#0000ff"/><text xml:space="preserve" y="21" x="' +
+      '40" font-size="12" stroke-width="0" stroke="#000000" fill="#000000">B' +
+      'lue</text><rect height="27" width="27" y="41" x="5" style="stroke-wid' +
+      'th:1;stroke:rgb(0,0,0)" fill="#ff00ff"/><text xml:space="preserve" y=' +
+      '"61" x="40" font-size="12" stroke-width="0" stroke="#000000" fill="#0' +
+      '00000">Purple</text><rect height="27" width="27" y="81" x="5" style="' +
+      'stroke-width:1;stroke:rgb(0,0,0)" fill="#000000"/><text xml:space="pr' +
+      'eserve" y="101" x="40" font-size="12" stroke-width="0" stroke="#00000' +
+      '0" fill="#000000">Black</text><rect height="27" width="27" y="121" x=' +
+      '"5" style="stroke-width:1;stroke:rgb(0,0,0)" fill="#00ffff"/><text xm' +
+      'l:space="preserve" y="141" x="40" font-size="12" stroke-width="0" str' +
+      'oke="#000000" fill="#000000">Yellow</text><rect height="27" width="27' +
+      '" y="161" x="5" style="stroke-width:1;stroke:rgb(0,0,0)" fill="#aa00b' +
+      'b"/><text xml:space="preserve" y="181" x="40" font-size="12" stroke-w' +
+      'idth="0" stroke="#000000" fill="#000000">Magenta</text></g></svg>';
+
+        names = ['Blue', 'Purple', 'Black', 'Yellow', 'Magenta'];
+      colors = ['#0000ff', '#ff00ff', '#000000', '#00ffff', '#aa00bb'];
+
+      res = formatSVGLegend(names, colors);
+      deepEqual(res, e, 'SVG file is formatted correcly');
+    });
+
+    /**
+     *
+     * Test that the SVG file is generated correctly when there are long labels.
+     *
+     */
+    test('Test formatSVGLegend works correctly with long names', function() {
+      var res, names = [], colors = [], exp = '';
+
+      e = '<svg xmlns="http://www.w3.org/2000/svg" width="1056" height="191"' +
+      '><g><rect height="27" width="27" y="1" x="5" style="stroke-width:1;st' +
+      'roke:rgb(0,0,0)" fill="#0000ff"/><text xml:space="preserve" y="21" x=' +
+      '"40" font-size="12" stroke-width="0" stroke="#000000" fill="#000000">' +
+      'Blue with more words (this is a long string)</text><rect height="27" ' +
+      'width="27" y="41" x="5" style="stroke-width:1;stroke:rgb(0,0,0)" fill' +
+      '="#ff00ff"/><text xml:space="preserve" y="61" x="40" font-size="12" s' +
+      'troke-width="0" stroke="#000000" fill="#000000">Purple</text><rect he' +
+      'ight="27" width="27" y="81" x="5" style="stroke-width:1;stroke:rgb(0,' +
+      '0,0)" fill="#000000"/><text xml:space="preserve" y="101" x="40" font-' +
+      'size="12" stroke-width="0" stroke="#000000" fill="#000000">Black but ' +
+      'not as long as blue</text><rect height="27" width="27" y="121" x="5" ' +
+      'style="stroke-width:1;stroke:rgb(0,0,0)" fill="#00ffff"/><text xml:sp' +
+      'ace="preserve" y="141" x="40" font-size="12" stroke-width="0" stroke=' +
+      '"#000000" fill="#000000">Yellow</text><rect height="27" width="27" y=' +
+      '"161" x="5" style="stroke-width:1;stroke:rgb(0,0,0)" fill="#aa00bb"/>' +
+      '<text xml:space="preserve" y="181" x="40" font-size="12" stroke-width' +
+      '="0" stroke="#000000" fill="#000000">Magenta</text></g></svg>';
+
+        names = ['Blue with more words (this is a long string)', 'Purple',
+      'Black but not as long as blue', 'Yellow', 'Magenta'];
+      colors = ['#0000ff', '#ff00ff', '#000000', '#00ffff', '#aa00bb'];
+
+      res = formatSVGLegend(names, colors);
+      deepEqual(res, e, 'SVG file is formatted correcly');
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_plottable.js b/tests/javascript_tests/test_plottable.js
new file mode 100644
index 0000000..c06edef
--- /dev/null
+++ b/tests/javascript_tests/test_plottable.js
@@ -0,0 +1,106 @@
+requirejs(['jquery', 'model'], function($, model) {
+  $(document).ready(function() {
+    var Plottable = model.Plottable;
+
+    module('Plottable', {
+
+      setup: function() {
+      },
+
+      teardown: function() {
+      }
+    });
+
+    /**
+     *
+     * Test that the Plottable object is initialized correctly, without
+     * optional arguments.
+     *
+     */
+    test('Test constructor', function() {
+      var plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2]);
+
+      equal(plot.name, 'foo', 'The name matches!');
+      deepEqual(plot.metadata, ['a', 'b', 'c'], 'The metadata match!');
+      deepEqual(plot.coordinates, [0.2, 0.3, 0.5, 0.2], 'The coordinates ' +
+          'match!');
+
+      // optional arguments get default values
+      equal(plot.idx, -1, 'The index value was set correctly!');
+      deepEqual(plot.ci, [], 'The confidence intervals were set correctly!');
+    });
+
+    /**
+     *
+     * Test that the Plottable object is initialized correctly, with optional
+     * arguments.
+     *
+     */
+    test('Test constructor optional+', function() {
+      var plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2], 1);
+
+      equal(plot.name, 'foo', 'The name matches!');
+      deepEqual(plot.metadata, ['a', 'b', 'c'], 'The metadata matches!');
+      deepEqual(plot.coordinates, [0.2, 0.3, 0.5, 0.2], 'The coordinates ' +
+          'match!');
+
+      equal(plot.idx, 1, 'The index value was set correctly!');
+      deepEqual(plot.ci, [], 'The confidence intervals were set correctly!');
+
+      plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2], 1,
+          [3, 2, 3, 4]);
+
+      equal(plot.name, 'foo', 'The name matches!');
+      deepEqual(plot.metadata, ['a', 'b', 'c'], 'The metadata matches!');
+      deepEqual(plot.coordinates, [0.2, 0.3, 0.5, 0.2], 'The coordinates ' +
+          'match!');
+
+      equal(plot.idx, 1, 'The index value was set correctly');
+      deepEqual(plot.ci, [3, 2, 3, 4], 'The confidence intervals were set ' +
+          'correctly');
+    });
+
+    /**
+     *
+     * Test that the Plottable object raises an exception with invalid
+     * arguments.
+     *
+     */
+    test('Test constructor exceptions', function() {
+      var result;
+
+      // check this happens for all the properties
+      throws(
+          function() {
+            result = new Plottable('foo', ['x', 'y', 'z'],
+                [0.2, 0.2, 0.5, 0, 111], 3, [0.2]);
+          },
+          Error,
+          'An error is raised if the number of coordinates does not ' +
+          'correspond to the number confidence intervals.'
+          );
+    });
+
+    test('Test toString method', function() {
+      //check what happens with toString
+      var plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2], 1);
+      equal(plot.toString(), 'Sample: foo located at: (0.2, 0.3, 0.5, 0.2) ' +
+          'metadata: [a, b, c] at index: 1 and without confidence intervals.',
+          'Test correctly converted Plottable to string type.');
+
+      plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2], 1,
+          [0.2, 0.05, 0.01, 0.2]);
+      equal(plot.toString(), 'Sample: foo located at: (0.2, 0.3, 0.5, 0.2) ' +
+          'metadata: [a, b, c] at index: 1 and with confidence intervals at ' +
+          '(0.2, 0.05, 0.01, 0.2).',
+          'Test correctly converted Plottable to string type with confidence' +
+          ' intervals.');
+
+      plot = new Plottable('foo', ['a', 'b', 'c'], [0.2, 0.3, 0.5, 0.2]);
+      equal(plot.toString(), 'Sample: foo located at: (0.2, 0.3, 0.5, 0.2) ' +
+          'metadata: [a, b, c] without index and without confidence intervals.',
+          'Test correctly converted Plottable to string type without index.');
+
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_scale_view_controller.js b/tests/javascript_tests/test_scale_view_controller.js
new file mode 100644
index 0000000..a22e492
--- /dev/null
+++ b/tests/javascript_tests/test_scale_view_controller.js
@@ -0,0 +1,213 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'three',
+    'model',
+    'view',
+    'viewcontroller',
+    'slickgrid',
+    'scaleviewcontroller'
+], function($, _, THREE, model, DecompositionView, viewcontroller, SlickGrid,
+            ScaleViewController) {
+  $(document).ready(function() {
+    var EmperorAttributeABC = viewcontroller.EmperorAttributeABC;
+    var DecompositionModel = model.DecompositionModel;
+    var Plottable = model.Plottable;
+
+    module('ScaleViewController', {
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+        var $slickid = $('<div id="fooligans"></div>');
+        $slickid.appendTo(document.body);
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635', 'PC.634'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Mixed', 'Treatment', 'DOB'];
+        metadata = [['PC.636', '14.2', 'Control', '20070314'],
+        ['PC.635', 'StringValue', 'Fast', '20071112'],
+        ['PC.634', '14.7', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        this.decomp = new DecompositionModel(name, ids, coords, pct_var,
+            md_headers, metadata);
+        this.dv = new DecompositionView(this.decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+
+        // Slickgrid
+        var columns = [
+        {id: 'pc1', name: 'pc1', field: 'pc1'},
+        {id: 'pc2', name: 'pc2', field: 'pc2'},
+        {id: 'pc3', name: 'pc3', field: 'pc3'}
+        ];
+
+        var options = {
+          enableCellNavigation: true,
+          enableColumnReorder: false
+        };
+        var data = [];
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 1});
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 2});
+        data.push({'pc1': 2, 'pc2': 1, 'pc3': 2});
+
+        grid = new Slick.Grid('#fooligans', data, columns, options);
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        $('#fooligans').remove();
+        this.decomp = undefined;
+      }
+    });
+
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+
+      assert.ok(ScaleViewController.prototype instanceof EmperorAttributeABC);
+
+      var controller = new ScaleViewController(
+        container, this.sharedDecompositionViewDict);
+      equal(controller.title, 'Scale');
+
+      var testColumn = controller.bodyGrid.getColumns()[0];
+      equal(testColumn.field, 'value');
+
+      // verify the checked value is set properly
+      equal(controller.$scaledValue.is(':checked'), false);
+      equal(controller.$select.val(), 'SampleID');
+    });
+
+    test('Testing setPlottableAttributes helper function', function(assert) {
+      // testing with one plottable
+      var idx = 0;
+      plottables = [{idx: idx}];
+      deepEqual(this.dv.markers[idx].scale.x, 1);
+      deepEqual(this.dv.markers[idx].scale.y, 1);
+      deepEqual(this.dv.markers[idx].scale.z, 1);
+      deepEqual(this.dv.markers[idx + 1].scale.x, 1);
+      deepEqual(this.dv.markers[idx + 1].scale.y, 1);
+      deepEqual(this.dv.markers[idx + 1].scale.z, 1);
+      ScaleViewController.prototype.setPlottableAttributes(
+        this.dv, 2.5, plottables);
+      deepEqual(this.dv.markers[idx].scale.x, 2.5);
+      deepEqual(this.dv.markers[idx].scale.y, 2.5);
+      deepEqual(this.dv.markers[idx].scale.z, 2.5);
+      deepEqual(this.dv.markers[idx + 1].scale.x, 1);
+      deepEqual(this.dv.markers[idx + 1].scale.y, 1);
+      deepEqual(this.dv.markers[idx + 1].scale.z, 1);
+      equal(this.dv.needsUpdate, true);
+
+      // testing with multiple plottable
+      plottables = [{idx: idx}, {idx: idx + 1}];
+      ScaleViewController.prototype.setPlottableAttributes(this.dv, 0.4,
+                                                           plottables);
+      deepEqual(this.dv.markers[idx].scale.x, 0.4);
+      deepEqual(this.dv.markers[idx].scale.y, 0.4);
+      deepEqual(this.dv.markers[idx].scale.z, 0.4);
+      deepEqual(this.dv.markers[idx + 1].scale.x, 0.4);
+      deepEqual(this.dv.markers[idx + 1].scale.y, 0.4);
+      deepEqual(this.dv.markers[idx + 1].scale.z, 0.4);
+      equal(this.dv.needsUpdate, true);
+    });
+
+    test('Testing toJSON', function() {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ScaleViewController(
+        container, this.sharedDecompositionViewDict);
+
+      var obs = controller.toJSON();
+      var exp = {category: 'SampleID', globalScale: '1.0', scaleVal: false,
+                 data: {'PC.636': 1, 'PC.635': 1, 'PC.634': 1}};
+      deepEqual(obs, exp);
+    });
+
+    test('Testing fromJSON', function() {
+      var json = {category: 'SampleID', globalScale: '1.0', scaleVal: false,
+                 data: {'PC.636': 1.1, 'PC.635': 1, 'PC.634': 0.7}};
+
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ScaleViewController(
+        container, this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+      var idx = 0;
+      var scatter = controller.decompViewDict.scatter;
+      deepEqual(scatter.markers[idx].scale.x, 1.1);
+      deepEqual(scatter.markers[idx].scale.y, 1.1);
+      deepEqual(scatter.markers[idx].scale.z, 1.1);
+      deepEqual(scatter.markers[idx + 1].scale.x, 1);
+      deepEqual(scatter.markers[idx + 1].scale.y, 1);
+      deepEqual(scatter.markers[idx + 1].scale.z, 1);
+      deepEqual(scatter.markers[idx + 2].scale.x, 0.7);
+      deepEqual(scatter.markers[idx + 2].scale.y, 0.7);
+      deepEqual(scatter.markers[idx + 2].scale.z, 0.7);
+      equal(controller.$select.val(), 'SampleID');
+      equal(controller.$scaledValue.is(':checked'), false);
+    });
+
+    test('Testing fromJSON scaled', function() {
+      var json = {category: 'DOB', globalScale: '1.0', scaleVal: true,
+                  data: {'20070314': 1, '20071112': 5}};
+
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ScaleViewController(
+        container, this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+      var idx = 0;
+      deepEqual(controller.decompViewDict.scatter.markers[idx].scale.x, 1);
+      deepEqual(controller.decompViewDict.scatter.markers[idx].scale.y, 1);
+      deepEqual(controller.decompViewDict.scatter.markers[idx].scale.z, 1);
+      deepEqual(controller.decompViewDict.scatter.markers[idx + 1].scale.x, 5);
+      deepEqual(controller.decompViewDict.scatter.markers[idx + 1].scale.y, 5);
+      deepEqual(controller.decompViewDict.scatter.markers[idx + 1].scale.z, 5);
+      equal(controller.$select.val(), 'DOB');
+      equal(controller.$scaledValue.is(':checked'), true);
+    });
+
+    test('Testing getScale', function() {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ScaleViewController(
+        container, this.sharedDecompositionViewDict);
+      var data = ['1.0', 'no', 'false', 'something', '2.0'];
+
+      //test standard values
+      var obs = controller.getScale(data, false);
+      var exp = {'1.0': 1, 'no': 1, 'false': 1, 'something': 1, '2.0': 1};
+      deepEqual(obs, exp);
+
+      //test scaled values
+      var obs = controller.getScale(data, true);
+      var exp = {'1': 1, 'no': 0, 'false': 0, 'something': 0, '2': 5};
+      deepEqual(obs, exp);
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_sceneplotview3d.js b/tests/javascript_tests/test_sceneplotview3d.js
new file mode 100644
index 0000000..c5d11ad
--- /dev/null
+++ b/tests/javascript_tests/test_sceneplotview3d.js
@@ -0,0 +1,529 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'scene3d',
+    'three',
+    'svgrenderer',
+    'orbitcontrols'
+], function($, _, model, DecompositionView, ScenePlotView3D, THREE,
+            SVGRenderer, OrbitControls) {
+  var DecompositionModel = model.DecompositionModel;
+  $(document).ready(function() {
+    module('ScenePlotView3D', {
+
+      setup: function() {
+        // global variable shared
+        this.sharedDecompositionViewDict = {};
+
+        var div = $('<div id="fooligans"></div>');
+        div.appendTo(document.body);
+
+        var name = 'pcoa';
+        var ids = ['PC.636', 'PC.635'];
+        var coords = [[-0.276542, -0.144964, 0.066647, -0.067711, 0.176070,
+        0.072969, -0.229889, -0.046599],
+        [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485,
+        -0.115211, -0.112864, 0.064794]];
+        var pct_var = [26.6887048633, 16.2563704022, 13.7754129161,
+                       11.217215823, 10.024774995, 8.22835130237,
+                       7.55971173665, 6.24945796136];
+        var md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment',
+                          'DOB'];
+        var metadata = [
+          ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+          ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']
+        ];
+        var decomp = new DecompositionModel(name, ids, coords, pct_var,
+            md_headers, metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+      },
+
+      teardown: function() {
+        // created as global during the setup function
+        this.sharedDecompositionViewDict = undefined;
+
+        // appended to the body during setup
+        $('#fooligans').remove();
+      }
+
+    });
+
+    /**
+     *
+     * Test the constructor for ScenePlotView3D
+     *
+     */
+    test('Test the constructor', function(assert) {
+
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // assert proper initializations for the attributes, we won't check their
+      // initialization values as these are subject to change
+      assert.ok(spv.renderer instanceof THREE.SVGRenderer);
+      assert.ok(spv.control instanceof THREE.OrbitControls);
+      assert.ok(spv.scene instanceof THREE.Scene);
+      assert.ok(spv.camera instanceof THREE.PerspectiveCamera);
+      assert.ok(spv.light instanceof THREE.DirectionalLight);
+
+      deepEqual(spv.xView, 0);
+      deepEqual(spv.yView, 0);
+
+      equal(spv.width, 20);
+      equal(spv.height, 20);
+      equal(spv.checkUpdate(), true);
+
+      equal(spv.axesColor, 0xFFFFFF);
+      equal(spv.backgroundColor, 0x000000);
+
+      deepEqual(spv.visibleDimensions, [0, 1, 2]);
+      deepEqual(spv.dimensionRanges.max, [-0.237661, 0.046053, 0.066647,
+                                          0.159061, 0.17607, 0.072969,
+                                          -0.112864, 0.064794]);
+      deepEqual(spv.dimensionRanges.min, [-1, -0.144964, -0.138136, -0.067711,
+                                          -0.247485, -0.115211, -0.229889,
+                                          -0.046599]);
+
+      // raycasting properties
+      assert.ok(spv._raycaster instanceof THREE.Raycaster);
+      assert.ok(spv._mouse instanceof THREE.Vector2);
+
+      // pub/sub
+      deepEqual(spv.EVENTS, ['click', 'dblclick']);
+      deepEqual(spv._subscribers.click.length, 1);
+      deepEqual(spv._subscribers.dblclick.length, 0);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test checkUpdate', function() {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.needsUpdate = false;
+      spv.decViews.scatter.needsUpdate = false;
+      spv.decViews.biplot.needsUpdate = false;
+      equal(spv.checkUpdate(), false);
+
+      spv.needsUpdate = true;
+      equal(spv.checkUpdate(), true);
+      spv.needsUpdate = false;
+
+      spv.decViews.scatter.needsUpdate = true;
+      equal(spv.checkUpdate(), true);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test checkUpdate background color', function() {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.needsUpdate = false;
+
+      spv.decViews.scatter.backgroundColor = 0x00FF00;
+      equal(spv.checkUpdate(), true);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test checkUpdate axes color', function() {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.needsUpdate = false;
+
+      spv.decViews.scatter.axesColor = 0x00FF00;
+      equal(spv.checkUpdate(), true);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test checkUpdate visible dimensions', function() {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.needsUpdate = false;
+
+      spv.decViews.scatter.visibleDimensions = [1, 2, 3];
+      equal(spv.checkUpdate(), true);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test the draw axes', function(assert) {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // color the axis lines
+      spv.drawAxesWithColor(0x00FF0F);
+
+      var line;
+
+      for (var i = 0; i < 3; i++) {
+        line = spv.scene.getObjectByName('emperor-axis-line-' + i);
+        equal(line.material.color.r, 0);
+        equal(line.material.color.g, 1);
+        equal(line.material.color.b, 0.058823529411764705);
+      }
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test removing axes', function(assert) {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // remove the axis lines
+      spv.removeAxes();
+
+      var line;
+
+      for (var i = 0; i < 3; i++) {
+        line = spv.scene.getObjectByName('emperor-axis-line-' + i);
+        assert.equal(line, undefined);
+      }
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+
+    test('Test the draw axes labels', function(assert) {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // color the axis lines
+      spv.drawAxesLabelsWithColor(0x00FF0F);
+
+      var label, positions = [[-0.237661, -0.144964, -0.138136],
+                              [-1, 0.046053, -0.138136],
+                              [-1, -0.144964, 0.066647]];
+
+      for (var i = 0; i < 3; i++) {
+        label = spv.scene.getObjectByName('emperor-axis-label-' + i);
+
+        equal(label.position.x, positions[i][0]);
+        equal(label.position.y, positions[i][1]);
+        equal(label.position.z, positions[i][2]);
+
+        equal(label.material.color.r, 0);
+        equal(label.material.color.g, 1);
+        equal(label.material.color.b, 0.058823529411764705);
+      }
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    test('Test removing axes labels', function(assert) {
+      // We will use SVGRenderer here and in the other tests as we cannot use
+      // WebGLRenderer and test with phantom.js
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // remove the axis lines
+      spv.removeAxesLabels();
+
+      var label;
+
+      for (var i = 0; i < 3; i++) {
+        label = spv.scene.getObjectByName('emperor-axis-label-' + i);
+        assert.equal(label, undefined);
+      }
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+
+    /**
+     *
+     * Test the setCameraAspectRatio method for ScenePlotView3D
+     *
+     */
+    test('Test setCameraAspectRatio', function() {
+
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.setCameraAspectRatio(100);
+      equal(spv.camera.aspect, 100);
+
+      spv.setCameraAspectRatio(200);
+      equal(spv.camera.aspect, 200);
+
+      spv.setCameraAspectRatio(1);
+      equal(spv.camera.aspect, 1);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /**
+     *
+     * Test the resize method for ScenePlotView3D
+     *
+     */
+    test('Test resize', function() {
+
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+      spv.resize(11, 11, 200, 300);
+
+      equal(spv.xView, 11);
+      equal(spv.yView, 11);
+
+      equal(spv.width, 200);
+      equal(spv.height, 300);
+
+      equal(spv.needsUpdate, true);
+
+      spv.resize(8, 6, 75, 309);
+
+      equal(spv.xView, 8);
+      equal(spv.yView, 6);
+
+      equal(spv.width, 75);
+      equal(spv.height, 309);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /**
+     *
+     * Test the render method for ScenePlotView3D
+     *
+     */
+    test('Test render', function(assert) {
+
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // Couldn't really find a way to properly test the render method as the
+      // properties it modifies are not publicly exposed by the renderer object.
+      // Therefore we will only call the method and if all goes well then the
+      // method shouldn't error or fail.
+      // spv.render();
+      // Update: turns out we cannot call the render method when we use the
+      // SVGRenderer class. Would be great if we find a way around this problem.
+      assert.ok(true);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /**
+     *
+     * Test exceptions are correctly raised on unknown events
+     *
+     */
+    test('Test off exceptions', function() {
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // check this happens for all the properties
+      throws(
+        function() {
+          spv.off('does not exist', function(a, b) { return a;});
+        }, Error, 'An error is raised if the event is unknown'
+      );
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /**
+     *
+     * Test exceptions are correctly raised on unknown events
+     *
+     */
+    test('Test on exceptions', function() {
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      // check this happens for all the properties
+      throws(
+        function() {
+          spv.on('does not exist', function(a, b) { return a;});
+        }, Error, 'An error is raised if the event is unknown'
+      );
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /*
+     *
+     * Testing raycasting-involved methods
+     *
+     * We need to setup a few mock methods and objects, otherwise we can't
+     * quite test the raycasting with the SVGRenderer.
+     *
+     * 1.- Setup a mock event that will be used to calculate the position of
+     * the mouse.
+     *
+     * 2.- Overwrite the intersectObjects method with a new function that
+     * returns a manufactured mock object.
+     *
+     * 3.- Finally, trigger the callback on 'click' and verify that the
+     * received objects are correct.
+     *
+     */
+
+    /**
+     *
+     * Test the 'click' callback is resolved
+     *
+     */
+    test('Verifying click works', function() {
+      // for the test to pass, two assertions should be made
+      expect(2);
+
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      spv.on('click', function(a, b) {
+        equal(a, 'Meshy McMeshface');
+        deepEqual(b, {'name': 'Meshy McMeshface'});
+      });
+
+      var mockEvent = {
+        'clientX': -0.276542,
+        'clientY': -0.144964,
+        'offsetLeft': 0,
+        'offsetTop': 0,
+        'width': 20,
+        'height': 20
+      };
+      mockEvent.preventDefault = function() {};
+
+      var meshy = {'object': {'name': 'Meshy McMeshface'}};
+      spv._raycaster.intersectObjects = function() { return [meshy]; };
+      spv._eventCallback('click', mockEvent);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /**
+     *
+     * Test the 'dblclick' callback is resolved
+     *
+     */
+    test('Verifying double click works', function() {
+      // for the test to pass, two assertions should be made
+      expect(2);
+
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      spv.on('dblclick', function(a, b) {
+        equal(a, 'Meshy McMeshface');
+        deepEqual(b, {'name': 'Meshy McMeshface'});
+      });
+
+      var mockEvent = {
+        'clientX': -0.276542,
+        'clientY': -0.144964,
+        'offsetLeft': 0,
+        'offsetTop': 0,
+        'width': 20,
+        'height': 20
+      };
+      mockEvent.preventDefault = function() {};
+
+      var meshy = {'object': {'name': 'Meshy McMeshface'}};
+      spv._raycaster.intersectObjects = function() { return [meshy]; };
+      spv._eventCallback('dblclick', mockEvent);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+    /*
+     *
+     * Check we can add/remove subscribers
+     *
+     */
+    test('Check removal and addition of subscribers', function() {
+      var renderer = new THREE.SVGRenderer({antialias: true});
+      var spv = new ScenePlotView3D(renderer, this.sharedDecompositionViewDict,
+                                    'fooligans', 0, 0, 20, 20);
+
+      var a = function() {
+        return 42;
+      };
+
+      var b = function() {
+        return 'forty two';
+      };
+
+      spv.on('click', a);
+      spv.on('click', b);
+      equal(spv._subscribers.click.length, 3);
+      spv.off('click', a);
+      equal(spv._subscribers.click.length, 2);
+      spv.off('click', b);
+      equal(spv._subscribers.click.length, 1);
+
+      // release the control back to the main page
+      spv.control.dispose();
+    });
+
+  });
+});
diff --git a/tests/javascript_tests/test_shape_controller.js b/tests/javascript_tests/test_shape_controller.js
new file mode 100644
index 0000000..9027d35
--- /dev/null
+++ b/tests/javascript_tests/test_shape_controller.js
@@ -0,0 +1,189 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'viewcontroller',
+    'three',
+    'shapecontroller',
+    'shape-editor',
+    'shapes'
+], function($, _, model, DecompositionView, viewcontroller, THREE,
+            ShapeController, ShapeEditor, shapes) {
+  $(document).ready(function() {
+    var EmperorAttributeABC = viewcontroller.EmperorAttributeABC;
+    var DecompositionModel = model.DecompositionModel;
+
+    module('Shape Controller', {
+      setup: function() {
+        // setup function
+        this.shapesAvailable = ['Sphere', 'Cube', 'Cone', 'Icosahedron',
+                                'Cylinder'];
+        this.sharedDecompositionViewDict = {};
+
+        // setup function
+        var name = 'pcoa';
+        var ids = ['PC.636', 'PC.635'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        var pct_var = [26.6887048633, 16.2563704022, 13.7754129161,
+                       11.217215823, 10.024774995, 8.22835130237,
+                       7.55971173665, 6.24945796136];
+        var md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment',
+                          'DOB'];
+        var metadata = [
+          ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+          ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']
+        ];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        this.decomp = new DecompositionModel(name, ids, coords, pct_var,
+                                             md_headers, metadata);
+        this.dv = new DecompositionView(this.decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+      },
+
+      teardown: function() {
+        // teardown function
+      }
+    });
+
+    test('Shapes dropdown', function() {
+      var values = [];
+      shapes.$shapesDropdown.find('option').each(function() {
+          values.push($(this).attr('value'));
+      });
+      deepEqual(values, this.shapesAvailable);
+    });
+
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+
+      assert.ok(ShapeController.prototype instanceof EmperorAttributeABC);
+
+      var controller = new ShapeController(container,
+                                           this.sharedDecompositionViewDict);
+      equal(controller.title, 'Shape');
+
+      var testColumn = controller.bodyGrid.getColumns()[0];
+      equal(testColumn.field, 'value');
+    });
+
+    test('Test getGeometry', function() {
+      var geom, range;
+
+      range = {'min': [-2, -1, -3], 'max': [3, 8, 9]};
+
+      geom = shapes.getGeometry('Sphere', range);
+      equal(geom.parameters.radius, 0.06);
+
+      geom = shapes.getGeometry('Cube', range);
+      equal(geom.parameters.width, 0.06);
+      equal(geom.parameters.height, 0.06);
+      equal(geom.parameters.depth, 0.06);
+
+      geom = shapes.getGeometry('Cone', range);
+      equal(geom.parameters.radiusTop, 0.024);
+      equal(geom.parameters.radiusBottom, 0);
+      equal(geom.parameters.height, 0.09);
+
+      geom = shapes.getGeometry('Icosahedron', range);
+      equal(geom.parameters.radius, 0.06);
+
+      geom = shapes.getGeometry('Cylinder', range);
+      equal(geom.parameters.radiusTop, 0.024);
+      equal(geom.parameters.radiusBottom, 0.024);
+      equal(geom.parameters.height, 0.09);
+    });
+
+    test('Check getGeometry raises an exception with unknown shape',
+         function() {
+      var range = {'min': [-2, -1, -3], 'max': [3, 8, 9]};
+      throws(function() {
+        shapes.getGeometry('Geometry McGeometryface', range);
+      }, Error, 'Throw error if unknown shape given');
+    });
+
+    test('Testing setPlottableAttributes helper function', function(assert) {
+      // testing with one plottable
+      var idx = 0;
+      plottables = [{idx: idx}];
+      equal(this.dv.markers[idx].geometry.type, 'SphereGeometry');
+      equal(this.dv.markers[idx + 1].geometry.type, 'SphereGeometry');
+      ShapeController.prototype.setPlottableAttributes(this.dv, 'Cube',
+                                                       plottables);
+      equal(this.dv.markers[idx].geometry.type, 'BoxGeometry');
+      equal(this.dv.markers[idx + 1].geometry.type, 'SphereGeometry');
+      equal(this.dv.needsUpdate, true);
+
+      // testing with multiple plottable
+      plottables = [{idx: idx}, {idx: idx + 1}];
+      ShapeController.prototype.setPlottableAttributes(this.dv, 'Cylinder',
+                                                       plottables);
+      equal(this.dv.markers[idx].geometry.type, 'CylinderGeometry');
+      equal(this.dv.markers[idx + 1].geometry.type, 'CylinderGeometry');
+      equal(this.dv.needsUpdate, true);
+    });
+
+    test('Testing setPlottableAttributes unknown shape', function(assert) {
+      // testing with one plottable
+      plottables = [{idx: idx}];
+      throws(function() {
+        ShapeController.prototype.setPlottableAttributes(this.dv, 'WEIRD',
+                                                         plottables);
+      }, Error, 'Throw error if unknown shape given');
+
+    });
+
+    test('Testing toJSON', function() {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ShapeController(container,
+                                           this.sharedDecompositionViewDict);
+
+      var obs = controller.toJSON();
+      var exp = {category: 'SampleID',
+                 data: {'PC.636': 'Sphere', 'PC.635': 'Sphere'}
+      };
+      deepEqual(obs, exp);
+    });
+
+    test('Testing fromJSON', function() {
+      var json = {'category': 'SampleID',
+                  'data': {'PC.636': 'Cube', 'PC.635': 'Sphere'}
+      };
+
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new ShapeController(container,
+                                           this.sharedDecompositionViewDict);
+
+      controller.fromJSON(json);
+      var idx = 0;
+      equal(controller.decompViewDict.scatter.markers[idx].geometry.type,
+            'BoxGeometry');
+      equal(controller.decompViewDict.scatter.markers[idx + 1].geometry.type,
+            'SphereGeometry');
+    });
+
+  });
+});
diff --git a/tests/javascript_tests/test_trajectory.js b/tests/javascript_tests/test_trajectory.js
new file mode 100644
index 0000000..5dad341
--- /dev/null
+++ b/tests/javascript_tests/test_trajectory.js
@@ -0,0 +1,528 @@
+requirejs(['underscore', 'trajectory'], function(_, trajectory) {
+  $(document).ready(function() {
+    var TrajectoryOfSamples = trajectory.TrajectoryOfSamples;
+    var getMinimumDelta = trajectory.getMinimumDelta;
+    var getSampleNamesAndDataForSortedTrajectories =
+      trajectory.getSampleNamesAndDataForSortedTrajectories;
+    var distanceBetweenPoints = trajectory.distanceBetweenPoints;
+    var linearInterpolation = trajectory.linearInterpolation;
+
+    // these variables are reused throughout this test suite
+    var mappingFileHeaders, mappingFileData, coordinatesData;
+    var sampleNames, gradientPoints, coordinates;
+
+    // these are expected results needed for multiple tests
+    var crunchedDataTwoCategories, crunchedDataOneCategory;
+
+    module('Trajectory', {
+
+      setup: function() {
+        // setup function
+        mappingFileHeaders = ['SampleID', 'LinkerPrimerSequence', 'Treatment',
+                              'DOB'];
+        mappingFileData = {
+          'PC.481': ['PC.481', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+          'PC.607': ['PC.607', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112'],
+          'PC.634': ['PC.634', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.635': ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.593': ['PC.593', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20071210'],
+          'PC.636': ['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20080116'],
+          'PC.355': ['PC.355', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+          'PC.354': ['PC.354', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061218'],
+          'PC.356': ['PC.356', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20061126']};
+
+        coordinatesData = new Array();
+        coordinatesData['PC.636'] = { 'name': 'PC.636', 'color': 0,
+          'x': -0.276542, 'y': -0.144964, 'z': 0.066647, 'P1': -0.276542,
+          'P2': -0.144964, 'P3': 0.066647, 'P4': -0.067711, 'P5': 0.176070,
+          'P6': 0.072969, 'P7': -0.229889, 'P8': -0.046599 };
+
+        coordinatesData['PC.635'] = { 'name': 'PC.635', 'color': 0, 'x':
+          -0.237661, 'y': 0.046053, 'z': -0.138136, 'P1': -0.237661, 'P2':
+            0.046053, 'P3': -0.138136, 'P4': 0.159061, 'P5': -0.247485, 'P6':
+            -0.115211, 'P7': -0.112864, 'P8': 0.064794 };
+        coordinatesData['PC.356'] = { 'name': 'PC.356', 'color': 0, 'x':
+          0.228820, 'y': -0.130142, 'z': -0.287149, 'P1': 0.228820, 'P2':
+            -0.130142, 'P3': -0.287149, 'P4': 0.086450, 'P5': 0.044295, 'P6':
+            0.206043, 'P7': 0.031000, 'P8': 0.071992 };
+        coordinatesData['PC.481'] = { 'name': 'PC.481', 'color': 0, 'x':
+          0.042263, 'y': -0.013968, 'z': 0.063531, 'P1': 0.042263, 'P2':
+            -0.013968, 'P3': 0.063531, 'P4': -0.346121, 'P5': -0.127814, 'P6':
+            0.013935, 'P7': 0.030021, 'P8': 0.140148 };
+        coordinatesData['PC.354'] = { 'name': 'PC.354', 'color': 0, 'x':
+          0.280399, 'y': -0.006013, 'z': 0.023485, 'P1': 0.280399, 'P2':
+            -0.006013, 'P3': 0.023485, 'P4': -0.046811, 'P5': -0.146624, 'P6':
+            0.005670, 'P7': -0.035430, 'P8': -0.255786 };
+        coordinatesData['PC.593'] = { 'name': 'PC.593', 'color': 0, 'x':
+          0.232873, 'y': 0.139788, 'z': 0.322871, 'P1': 0.232873, 'P2':
+            0.139788, 'P3': 0.322871, 'P4': 0.183347, 'P5': 0.020466, 'P6':
+            0.054059, 'P7': -0.036625, 'P8': 0.099824 };
+        coordinatesData['PC.355'] = { 'name': 'PC.355', 'color': 0, 'x':
+          0.170518, 'y': -0.194113, 'z': -0.030897, 'P1': 0.170518, 'P2':
+            -0.194113, 'P3': -0.030897, 'P4': 0.019809, 'P5': 0.155100, 'P6':
+            -0.279924, 'P7': 0.057609, 'P8': 0.024248 };
+        coordinatesData['PC.607'] = { 'name': 'PC.607', 'color': 0, 'x':
+          -0.091330, 'y': 0.424147, 'z': -0.135627, 'P1': -0.091330, 'P2':
+            0.424147, 'P3': -0.135627, 'P4': -0.057519, 'P5': 0.151363, 'P6':
+            -0.025394, 'P7': 0.051731, 'P8': -0.038738 };
+        coordinatesData['PC.634'] = { 'name': 'PC.634', 'color': 0, 'x':
+          -0.349339, 'y': -0.120788, 'z': 0.115275, 'P1': -0.349339, 'P2':
+            -0.120788, 'P3': 0.115275, 'P4': 0.069495, 'P5': -0.025372, 'P6':
+            0.067853, 'P7': 0.244448, 'P8': -0.059883 };
+
+        sampleNames = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354'];
+        gradientPoints = [1, 4, 6, 8, 11];
+        coordinates = [{'x': 0, 'y': 0, 'z': 0}, {'x': 1, 'y': 1, 'z': 1},
+        {'x': -9, 'y': -9, 'z': -9}, {'x': 3, 'y': 3, 'z': 3},
+        {'x': 8, 'y': 8, 'z': 8}];
+
+        crunchedDataOneCategory = {'YATGCTGCCTCCCGTAGGAGT': [
+          { 'name': 'PC.356', 'value': '20061126', 'x': 0.22882, 'y':
+            -0.130142, 'z': -0.287149},
+          { 'name': 'PC.355', 'value': '20061218', 'x': 0.170518, 'y':
+            -0.194113, 'z': -0.030897},
+          { 'name': 'PC.354', 'value': '20061218', 'x': 0.280399, 'y':
+            -0.006013, 'z': 0.023485},
+          { 'name': 'PC.481', 'value': '20070314', 'x': 0.042263, 'y':
+            -0.013968, 'z': 0.063531},
+          { 'name': 'PC.607', 'value': '20071112', 'x': -0.09133, 'y':
+            0.424147, 'z': -0.135627},
+          { 'name': 'PC.593', 'value': '20071210', 'x': 0.232873, 'y':
+            0.139788, 'z': 0.322871},
+          { 'name': 'PC.634', 'value': '20080116', 'x': -0.349339, 'y':
+            -0.120788, 'z': 0.115275},
+          { 'name': 'PC.635', 'value': '20080116', 'x': -0.237661, 'y':
+            0.046053, 'z': -0.138136},
+          { 'name': 'PC.636', 'value': '20080116', 'x': -0.276542, 'y':
+            -0.144964, 'z': 0.066647}
+        ]
+        };
+
+        crunchedDataTwoCategories = expectedResult = {'Control': [
+          {'name': 'PC.356', 'value': '20061126', 'x': 0.22882, 'y': -0.130142,
+            'z': -0.287149},
+          {'name': 'PC.355', 'value': '20061218', 'x': 0.170518, 'y':
+            -0.194113, 'z': -0.030897},
+          {'name': 'PC.354', 'value': '20061218', 'x': 0.280399, 'y':
+            -0.006013, 'z': 0.023485},
+          {'name': 'PC.481', 'value': '20070314', 'x': 0.042263, 'y':
+            -0.013968, 'z': 0.063531},
+          {'name': 'PC.593', 'value': '20071210', 'x': 0.232873, 'y': 0.139788,
+            'z': 0.322871}
+        ],
+        'Fast': [
+        {'name': 'PC.607', 'value': '20071112', 'x': -0.09133, 'y': 0.424147,
+          'z': -0.135627},
+        {'name': 'PC.634', 'value': '20080116', 'x': -0.349339, 'y': -0.120788,
+          'z': 0.115275},
+        {'name': 'PC.635', 'value': '20080116', 'x': -0.237661, 'y': 0.046053,
+          'z': -0.138136},
+        {'name': 'PC.636', 'value': '20080116', 'x': -0.276542, 'y': -0.144964,
+          'z': 0.066647}
+        ]
+        };
+      },
+
+      teardown: function() {
+        // teardown function
+        mappingFileHeaders = null;
+        mappingFileData = null;
+        coordinatesData = null;
+
+        sampleNames = null;
+        gradientPoints = null;
+        coordinates = null;
+      }
+
+    });
+
+    /**
+     *
+     * Test that the trajectory object can be constructed without any problems
+     * and check that the attributes are set correctly.
+     *
+     */
+    test('Test constructor', function() {
+      var trajectory;
+
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          10);
+      deepEqual(trajectory.sampleNames, ['PC.636', 'PC.635', 'PC.356',
+          'PC.481', 'PC.354'], 'Sample names are set correctly');
+      equal(trajectory.metadataCategoryName, 'Treatment', 'Metadata ' +
+          'category name is set correctly');
+      deepEqual(trajectory.gradientPoints, [1, 4, 6, 8, 11], 'Gradient ' +
+          'point values are set correctly');
+      deepEqual(trajectory.coordinates, [{'x': 0, 'y': 0, 'z': 0},
+          {'x': 1, 'y': 1, 'z': 1}, {'x': -9, 'y': -9, 'z': -9},
+          {'x': 3, 'y': 3, 'z': 3}, {'x': 8, 'y': 8, 'z': 8}], 'Coordinates' +
+          ' values are set correctly');
+      equal(trajectory.minimumDelta, 2, 'Minimum delta is set correctly');
+      equal(trajectory.suppliedN, 10, 'Value of N is set correctly');
+
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints,
+          coordinates, 2);
+      deepEqual(trajectory.sampleNames, ['PC.636', 'PC.635', 'PC.356',
+          'PC.481', 'PC.354'], 'Sample names are set correctly');
+      equal(trajectory.metadataCategoryName, 'Treatment', 'Metadata ' +
+          'category name is set correctly');
+      deepEqual(trajectory.gradientPoints, [1, 4, 6, 8, 11], 'Gradient' +
+          ' point values are set correctly');
+      deepEqual(trajectory.coordinates, [{'x': 0, 'y': 0, 'z': 0},
+          {'x': 1, 'y': 1, 'z': 1}, {'x': -9, 'y': -9, 'z': -9},
+          {'x': 3, 'y': 3, 'z': 3}, {'x': 8, 'y': 8, 'z': 8}], 'Coordinates' +
+          ' values are set correctly');
+      equal(trajectory.minimumDelta, 2, 'Minimum delta is set correctly');
+      equal(trajectory.suppliedN, 5, 'Default value of N is set to 5');
+    });
+
+    /**
+     *
+     * Test the trajectory object raises the appropriate errors when
+     * constructing with bad arguments.
+     *
+     */
+    test('Test constructor exceptions', function() {
+      var result;
+
+      // check this happens for all the properties
+      throws(
+          function() {
+            result = new TrajectoryOfSamples(sampleNames, 'foo', [1, 2, 3],
+                coordinates);
+          },
+          Error,
+          'An error is raised if the number of coordinates does not ' +
+          'correspond to the number of gradient points'
+          );
+    });
+
+    /**
+     *
+     * Test the trajectory object computes the interpolated coordinates
+     * correctly
+     *
+     */
+    test('Test _generateInterpolatedCoordinates', function() {
+
+      var trajectory;
+      var expectedInterpolatedCoordinates = [{ 'x': 0, 'y': 0, 'z': 0},
+      { 'x': 0.1, 'y': 0.1, 'z': 0.1},
+      { 'x': 0.2, 'y': 0.2, 'z': 0.2},
+      { 'x': 0.30000000000000004, 'y': 0.30000000000000004,
+        'z': 0.30000000000000004},
+      { 'x': 0.4, 'y': 0.4, 'z': 0.4},
+      { 'x': 0.5, 'y': 0.5, 'z': 0.5},
+      { 'x': 0.6000000000000001, 'y': 0.6000000000000001,
+        'z': 0.6000000000000001},
+      { 'x': 0.7000000000000001, 'y': 0.7000000000000001,
+        'z': 0.7000000000000001},
+      { 'x': 0.8, 'y': 0.8, 'z': 0.8},
+      { 'x': 0.9, 'y': 0.9, 'z': 0.9},
+      { 'x': 1, 'y': 1, 'z': 1},
+      { 'x': 0, 'y': 0, 'z': 0},
+      { 'x': -1, 'y': -1, 'z': -1},
+      { 'x': -2, 'y': -2, 'z': -2},
+      { 'x': -3, 'y': -3, 'z': -3},
+      { 'x': -4, 'y': -4, 'z': -4},
+      { 'x': -5, 'y': -5, 'z': -5},
+      { 'x': -6, 'y': -6, 'z': -6},
+      { 'x': -7, 'y': -7, 'z': -7},
+      { 'x': -8, 'y': -8, 'z': -8},
+      { 'x': -9, 'y': -9, 'z': -9},
+      { 'x': -7.8, 'y': -7.8, 'z': -7.8},
+      { 'x': -6.6, 'y': -6.6, 'z': -6.6},
+      { 'x': -5.4, 'y': -5.4, 'z': -5.4},
+      { 'x': -4.2, 'y': -4.2, 'z': -4.2},
+      { 'x': -3, 'y': -3, 'z': -3},
+      { 'x': -1.8000000000000007, 'y': -1.8000000000000007,
+        'z': -1.8000000000000007},
+      { 'x': -0.5999999999999996, 'y': -0.5999999999999996,
+        'z': -0.5999999999999996},
+      { 'x': 0.5999999999999996, 'y': 0.5999999999999996,
+        'z': 0.5999999999999996},
+      { 'x': 1.799999999999999, 'y': 1.799999999999999,
+        'z': 1.799999999999999},
+      { 'x': 3, 'y': 3, 'z': 3},
+      { 'x': 3.5, 'y': 3.5, 'z': 3.5},
+      { 'x': 4, 'y': 4, 'z': 4},
+      { 'x': 4.5, 'y': 4.5, 'z': 4.5},
+      { 'x': 5, 'y': 5, 'z': 5},
+      { 'x': 5.5, 'y': 5.5, 'z': 5.5},
+      { 'x': 6, 'y': 6, 'z': 6},
+      { 'x': 6.5, 'y': 6.5, 'z': 6.5},
+      { 'x': 7, 'y': 7, 'z': 7},
+      { 'x': 7.5, 'y': 7.5, 'z': 7.5},
+      { 'x': 8, 'y': 8, 'z': 8}];
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          10);
+
+      // test the interpolated values and the interval values
+      deepEqual(trajectory.interpolatedCoordinates,
+          expectedInterpolatedCoordinates,
+          'Check the interpolated coordinates are computed correctly');
+      deepEqual(trajectory._intervalValues, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+          1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+          3, 3, 3, 3, 3, 3, 3, 3] , 'Check the intervals array is ' +
+          'created properyl');
+
+      expectedInterpolatedCoordinates = [{'x': 0, 'y': 0, 'z': 0},
+      {'x': 0.25, 'y': 0.25, 'z': 0.25},
+      {'x': 0.5, 'y': 0.5, 'z': 0.5},
+      {'x': 0.75, 'y': 0.75, 'z': 0.75},
+      {'x': 1, 'y': 1, 'z': 1},
+      {'x': -2.3333333333333335, 'y': -2.3333333333333335,
+        'z': -2.3333333333333335},
+      {'x': -5.666666666666667, 'y': -5.666666666666667,
+        'z': -5.666666666666667},
+      {'x': -9, 'y': -9, 'z': -9},
+      {'x': -5, 'y': -5, 'z': -5},
+      {'x': -1, 'y': -1, 'z': -1},
+      {'x': 3, 'y': 3, 'z': 3},
+      {'x': 4.25, 'y': 4.25, 'z': 4.25},
+      {'x': 5.5, 'y': 5.5, 'z': 5.5},
+      {'x': 6.75, 'y': 6.75, 'z': 6.75},
+      {'x': 8, 'y': 8, 'z': 8 }];
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          3);
+      deepEqual(trajectory.interpolatedCoordinates,
+          expectedInterpolatedCoordinates,
+          'Check the interpolated coordinates are computed correctly');
+      deepEqual(trajectory._intervalValues,
+          [0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3] ,
+          'Check the interpolated coordinates are computed correctly');
+    });
+
+    /**
+     *
+     * Test the trajectory object retrieves only the needed points for a given
+     * index (edge cases).
+     *
+     */
+    test('Test representativeCoordinatesAtIndex edge cases', function() {
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          3);
+      deepEqual(trajectory.representativeCoordinatesAtIndex(0),
+          [{'x': 0, 'y': 0, 'z': 0}],
+          'Returns an empty array for index 0');
+
+      var expectedCoordinates = [{'x': 0, 'y': 0, 'z': 0},
+      {'x': 1, 'y': 1, 'z': 1},
+      {'x': -9, 'y': -9, 'z': -9},
+      {'x': 3, 'y': 3, 'z': 3},
+      {'x': 8, 'y': 8, 'z': 8}];
+      // the interpolated array is 18 samples long
+      deepEqual(trajectory.representativeCoordinatesAtIndex(18),
+          expectedCoordinates, 'Returns an array with only the ' +
+          'original coordinates');
+      deepEqual(trajectory.representativeCoordinatesAtIndex(100),
+          expectedCoordinates, 'Returns an array with only the ' +
+          'original coordinates');
+    });
+
+    /**
+     *
+     * Test the trajectory object retrieves only the needed points for a given
+     * index.
+     *
+     */
+    test('Test representativeCoordinatesAtIndex', function() {
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          3);
+
+      var expectedCoordinates = [{'x': 0, 'y': 0, 'z': 0},
+      {'x': 1, 'y': 1, 'z': 1},
+      {'x': -9, 'y': -9, 'z': -9},
+      {'x': 3, 'y': 3, 'z': 3},
+      {'x': 8, 'y': 8, 'z': 8}];
+
+      var expectedInterpolatedCoordinates = [{'x': 0, 'y': 0, 'z': 0},
+      {'x': 0.25, 'y': 0.25, 'z': 0.25},
+      {'x': 0.5, 'y': 0.5, 'z': 0.5},
+      {'x': 0.75, 'y': 0.75, 'z': 0.75},
+      {'x': 1, 'y': 1, 'z': 1},
+      {'x': -2.3333333333333335, 'y': -2.3333333333333335,
+        'z': -2.3333333333333335},
+      {'x': -5.666666666666667, 'y': -5.666666666666667,
+        'z': -5.666666666666667},
+      {'x': -9, 'y': -9, 'z': -9},
+      {'x': -5, 'y': -5, 'z': -5},
+      {'x': -1, 'y': -1, 'z': -1},
+      {'x': 3, 'y': 3, 'z': 3},
+      {'x': 4.25, 'y': 4.25, 'z': 4.25},
+      {'x': 5.5, 'y': 5.5, 'z': 5.5},
+      {'x': 6.75, 'y': 6.75, 'z': 6.75},
+      {'x': 8, 'y': 8, 'z': 8}];
+
+      deepEqual(trajectory.representativeCoordinatesAtIndex(3),
+          [{'x': 0, 'y': 0, 'z': 0},
+          {'x': 0.75, 'y': 0.75, 'z': 0.75}],
+          'Coordinates are retrieved correctly at index 3');
+      deepEqual(trajectory.representativeCoordinatesAtIndex(11),
+          [{'x': 0, 'y': 0, 'z': 0}, {'x': 1, 'y': 1, 'z': 1},
+          {'x': -9, 'y': -9, 'z': -9}, {'x': 3, 'y': 3, 'z': 3},
+          {'x': 4.25, 'y': 4.25, 'z': 4.25}],
+          'Coordinates are retrieved correctly at index 11');
+
+    });
+
+    /**
+     *
+     * Test the trajectory object computes the number of points for a given
+     * delta correctly.
+     *
+     */
+    test('Test calculateNumberOfPointsForDelta', function() {
+      var trajectory;
+
+      trajectory = new TrajectoryOfSamples(sampleNames, 'Treatment',
+          gradientPoints, coordinates, 2,
+          10);
+      equal(trajectory.calculateNumberOfPointsForDelta(3), 15, 'Number of ' +
+          'points for delta is calculated correctly');
+      equal(trajectory.calculateNumberOfPointsForDelta(8), 40, 'Number of ' +
+          'points for delta is calculated correctly');
+      equal(trajectory.calculateNumberOfPointsForDelta(7), 35, 'Number of ' +
+          'points for delta is calculated correctly');
+      equal(trajectory.calculateNumberOfPointsForDelta(11), 55, 'Number of ' +
+          'points for delta is calculated correctly');
+      equal(trajectory.calculateNumberOfPointsForDelta(1), 5, 'Number of ' +
+          'points for delta is calculated correctly');
+    });
+
+    /**
+     *
+     * Test linearInterpolation function.
+     *
+     */
+    test('Test linearInterpolation', function() {
+      var result;
+      result = linearInterpolation(0, 0, 0, 1, 1, 1, 5);
+      expectedResult = [{ 'x': 0, 'y': 0, 'z': 0},
+      {'x': 0.2, 'y': 0.2, 'z': 0.2},
+      { 'x': 0.4, 'y': 0.4, 'z': 0.4 },
+      { 'x': 0.6000000000000001, 'y': 0.6000000000000001,
+        'z': 0.6000000000000001 },
+      { 'x': 0.8, 'y': 0.8, 'z': 0.8 },
+      { 'x': 1, 'y': 1, 'z': 1}];
+      deepEqual(result, expectedResult, 'Linear interpolation is computed ' +
+          'correctly');
+
+        result = linearInterpolation(0, 0, 0, -1, -1, -1, 5);
+      expectedResult = [{ 'x': 0, 'y': 0, 'z': 0},
+      {'x': -0.2, 'y': -0.2, 'z': -0.2},
+      { 'x': -0.4, 'y': -0.4, 'z': -0.4 },
+      { 'x': -0.6000000000000001, 'y': -0.6000000000000001,
+        'z': -0.6000000000000001 },
+      { 'x': -0.8, 'y': -0.8, 'z': -0.8 },
+      { 'x': -1, 'y': -1, 'z': -1}];
+      deepEqual(result, expectedResult, 'Linear interpolation is computed ' +
+          'correctly');
+    });
+
+    /**
+     *
+     * Test distanceBetweenPoints function.
+     *
+     */
+    test('Test distanceBetweenPoints', function() {
+      var result;
+      result = distanceBetweenPoints(0, 0, 0, 1, 1, 1);
+      equal(result, Math.sqrt(3), 'Distance between points is computed' +
+          'correctly');
+
+      result = distanceBetweenPoints(-4, -3, -2, 84, 2, 11);
+      equal(result, 89.09545442950498, 'Distance between points is computed ' +
+          'correctly');
+
+      result = distanceBetweenPoints(0, 0, 0, 0, 0, 0);
+      equal(result, 0, 'Distance between points is computed correctly');
+
+      result = distanceBetweenPoints(-3, 17, -8888, 11, 0, 1);
+      equal(result, 8889.027280867125, 'Distance between points is computed ' +
+          'correctly');
+
+    });
+
+    /**
+     *
+     * Test getSampleNamesAndDataForSortedTrajectories function.
+     *
+     */
+    test('Test getSampleNamesAndDataForSortedTrajectories', function() {
+      var result, expectedResult;
+
+      result = getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+          mappingFileData,
+          coordinatesData,
+          'Treatment',
+          'DOB');
+      deepEqual(result, crunchedDataTwoCategories, 'The data is computed ' +
+          'correctly for two trajectories');
+
+      result = getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+          mappingFileData,
+          coordinatesData,
+          'LinkerPrimerSequence',
+          'DOB');
+      deepEqual(result, crunchedDataOneCategory, 'The data is computed ' +
+          'correctly for a single trajectory');
+    });
+
+    /**
+     *
+     * Test getSampleNamesAndDataForSortedTrajectories function raises the
+     * appropriate errors.
+     *
+     */
+    test('Test getSampleNamesAndDataForSortedTrajectories errors', function() {
+      throws(function() {
+        result = getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+            mappingFileData,
+            coordinatesData,
+            'DOB',
+            'BAZ');
+      }, Error, 'Error is thrown when a category is not found');
+
+      throws(function() {
+        result = getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+            mappingFileData,
+            coordinatesData,
+            'SPAM',
+            'DOB');
+      }, Error, 'Error is thrown when a category is not found');
+
+      throws(function() {
+        result = getSampleNamesAndDataForSortedTrajectories(mappingFileHeaders,
+            mappingFileData,
+            coordinatesData,
+            'FOO',
+            'BAR');
+      }, Error, 'Error is thrown when a category is not found');
+
+    });
+
+    /**
+     *
+     * Test getMinimumDelta function computes data correctly.
+     *
+     */
+    test('Test getMinimumDelta function', function() {
+      var result;
+      result = getMinimumDelta(crunchedDataOneCategory);
+      equal(result, 92, 'The minimum delta is computed correctly for one ' +
+          'category');
+
+      result = getMinimumDelta(crunchedDataTwoCategories);
+      equal(result, 92, 'The minimum delta is computed correctly for one ' +
+          'category');
+    });
+
+  });
+});
diff --git a/tests/javascript_tests/test_util.js b/tests/javascript_tests/test_util.js
new file mode 100644
index 0000000..dd3db94
--- /dev/null
+++ b/tests/javascript_tests/test_util.js
@@ -0,0 +1,161 @@
+requirejs(['jquery', 'underscore', 'util'], function($, _, util) {
+  var naturalSort = util.naturalSort, truncateLevel = util.truncateLevel,
+  convertXMLToString = util.convertXMLToString,
+  escapeRegularExpression = util.escapeRegularExpression,
+  cleanHTML = util.cleanHTML;
+  $(document).ready(function() {
+
+    module('General utilities', {
+
+      setup: function() {
+      },
+
+      teardown: function() {
+      }
+
+    });
+
+    /**
+     *
+     * Test that elements in the list are sorted correctly when only words are
+     * contained.
+     *
+     */
+    test('Test naturalSort with words only', function() {
+      var res, elements;
+
+      elements = ['foo', 'Bar', 'BAZ', 'duck', 'duck', 'go'];
+      res = naturalSort(elements);
+      deepEqual(res, ['Bar', 'BAZ', 'duck', 'duck', 'foo', 'go'],
+                'Arrays is sorted correctly');
+
+      elements = ['foo', 'foo', 'FOO', 'FoO', 'FOOOO', 'fOO'];
+      res = naturalSort(elements);
+      deepEqual(res, ['foo', 'foo', 'FOO', 'FoO', 'fOO', 'FOOOO'], 'Arrays ' +
+                'is sorted correctly');
+
+      elements = ['a', 'c', 'X', 'Y', 'Z', 'y'];
+      res = naturalSort(elements);
+      deepEqual(res, ['a', 'c', 'X', 'Y', 'y', 'Z'], 'Arrays is sorted ' +
+          'correctly');
+
+    });
+
+    /**
+     *
+     * Test that elements in the list are sorted correctly when only numbers
+     * are contained.
+     *
+     */
+    test('Test naturalSort with numbers only', function() {
+      var res, elements;
+
+      elements = ['8', '7', '3', '2', '1', '0'];
+      res = naturalSort(elements);
+      deepEqual(res, ['0', '1', '2', '3', '7', '8'], 'Arrays is ' +
+          'sorted correctly');
+
+      elements = ['1', '2', '3', '4', '5', '0'];
+      res = naturalSort(elements);
+      deepEqual(res, ['0', '1', '2', '3', '4', '5'], 'Arrays is ' +
+          'sorted correctly');
+
+      elements = ['-100', '0', '-0', '-200', '100', '100.001'];
+      res = naturalSort(elements);
+      deepEqual(res, ['-200', '-100', '0', '-0', '100', '100.001'],
+                'Arrays is sorted correctly');
+
+    });
+
+    test('Test Taxonomy Truncation', function() {
+      lineage = 'k__qwerf;p__asdfjkj;c__';
+
+        //Test if default string works
+        res = truncateLevel(lineage, 0);
+      equal(res, lineage);
+
+      //Test if first taxonomy works
+      res = truncateLevel(lineage, 1);
+      equal(res, 'k__qwerf');
+
+      //Test if second taxonomy works
+      res = truncateLevel(lineage, 2);
+      equal(res, 'p__asdfjkj');
+
+      //Make sure that last known taxonomy is displayed
+      res = truncateLevel(lineage, 3);
+      equal(res, 'p__asdfjkj;c__');
+
+      //Make sure that second taxonomy doesn't change
+      res = truncateLevel(lineage, 4);
+      equal(res, 'p__asdfjkj;c__');
+
+    });
+
+    /**
+     *
+     * Test that elements in the list are sorted correctly when there's a
+     * mixture of numbers and words.
+     *
+     */
+    test('Test naturalSort with numbers only', function() {
+      var res, elements;
+
+      elements = ['foo', '7', 'bar', '2', 'baz', '0'];
+      res = naturalSort(elements);
+      deepEqual(res, ['bar', 'baz', 'foo', '0', '2', '7'], 'Arrays is sorted ' +
+          'correctly');
+
+      elements = ['Foo', 'floo', 'BAAARR', '-1', '2', '0'];
+      res = naturalSort(elements);
+      deepEqual(res, ['BAAARR', 'floo', 'Foo', '-1', '0', '2'], 'Arrays is ' +
+          'sorted correctly');
+
+      elements = ['lorem', 'ipsum', 'boom.mooo', '-2.345563353', '-2.4'];
+      res = naturalSort(elements);
+      deepEqual(res, ['boom.mooo', 'ipsum', 'lorem', '-2.4', '-2.345563353'],
+          'Arrays is sorted correctly');
+
+    });
+
+    test('Test convertXMLToString', function() {
+      var el;
+
+      el = document.createElement('p');
+      el.appendChild(document.createTextNode('Test'));
+      equal(cleanHTML(convertXMLToString(el)),
+          cleanHTML('<p xmlns="http://www.w3.org/1999/xhtml">Test</p>'),
+          'Test a parragraph tag is converted correctly');
+
+      el = document.createElement('div');
+      el.appendChild(document.createTextNode('Test'));
+      el.className = 'test-div-class';
+        equal(cleanHTML(convertXMLToString(el)),
+            cleanHTML('<div xmlns="http://www.w3.org/1999/xhtml" ' +
+                      'class="test-div-class">Test</div>'),
+            'Test a div tag is converted correctly');
+    });
+
+    test('Test splitNumericValues', function() {
+      var values = ['1.112', 'stringvalue', '', 'Other String Value', '-2.2',
+                    '4', null, undefined, NaN, Infinity, -Infinity, 0, [],
+                    ['string', 1.0], [1.0, 'string'], {}, {key: 'val'}];
+      var numeric = [1.112, -2.2, 4, 0];
+      var nonNumeric = ['stringvalue', '', 'Other String Value', null,
+                        undefined, NaN, Infinity, -Infinity, [],
+                        ['string', 1.0], [1.0, 'string'], {}, {key: 'val'}];
+
+      var split = util.splitNumericValues(values);
+      deepEqual(split.numeric, numeric);
+      deepEqual(split.nonNumeric, nonNumeric);
+    });
+
+    test('Test regular expressions are escaped correctly', function() {
+      equal(escapeRegularExpression('some.sample.id'), 'some\\.sample\\.id');
+      equal(escapeRegularExpression('some-sample.id'), 'some\\-sample\\.id');
+      equal(escapeRegularExpression('s/.*?ome.sample.id'),
+                                    's/\\.\\*\\?ome\\.sample\\.id');
+    });
+
+  });
+});
diff --git a/tests/javascript_tests/test_view_controller.js b/tests/javascript_tests/test_view_controller.js
new file mode 100644
index 0000000..e719355
--- /dev/null
+++ b/tests/javascript_tests/test_view_controller.js
@@ -0,0 +1,444 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'abcviewcontroller',
+    'viewcontroller',
+    'slickgrid'
+], function($, _, model, DecompositionView, abcviewcontroller, viewcontroller,
+            SlickGrid) {
+  var EmperorViewControllerABC = abc.EmperorViewControllerABC;
+  var EmperorViewController = viewcontroller.EmperorViewController;
+  var EmperorAttributeABC = viewcontroller.EmperorAttributeABC;
+  var DecompositionModel = model.DecompositionModel;
+
+  $(document).ready(function() {
+
+    module('EmperorViewControllerABC', {
+    });
+
+    /**
+     *
+     * Test that the constructor for EmperorViewControllerABC.
+     *
+     */
+    test('Constructor tests', function(assert) {
+
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new EmperorViewControllerABC(container, 'foo', 'bar');
+
+      equal(controller.title, 'foo', 'Check the title is correctly set');
+      equal(controller.description, 'bar',
+            'Check the description is correctly set');
+      equal(controller.$container.id, container.id, 'Check the id of the ' +
+          'parent is correct');
+      equal(controller.active, false, 'Check the active property');
+      equal(controller.identifier.slice(0, 7), 'EMPtab-',
+            'Check the identifier property');
+      parseFloat(controller.identifier.slice(7));
+      equal(controller.enabled, true, 'Check the enabled property');
+
+      // check all the elements were successfully created
+      assert.ok(controller.$canvas.length);
+      assert.ok(controller.$header.length);
+      assert.ok(controller.$body.length);
+
+      assert.ok($.contains(controller.$canvas[0], controller.$header[0]));
+      assert.ok($.contains(controller.$canvas[0], controller.$body[0]));
+
+      equal(controller.$body.width(), 12);
+      equal(controller.$body.height(), 11);
+
+    });
+
+    /**
+     *
+     * Test the enabled method
+     *
+     */
+    test('Test the enabled method works', function() {
+
+      var container = $('<div id="does-not-exist"></div>');
+      var controller = new EmperorViewControllerABC(container, 'foo', 'bar');
+
+      equal(controller.enabled, true);
+      controller.setEnabled(false);
+      equal(controller.enabled, false);
+
+      throws(function() {
+        controller.setEnabled('shenanigans');
+      }, Error, 'setEnabled can only take a boolean');
+    });
+
+    /**
+     *
+     * Test the enabled method
+     *
+     */
+    test('Test the setActive method works', function() {
+
+      var container = $('<div id="does-not-exist"></div>');
+      var controller = new EmperorViewControllerABC(container, 'foo', 'bar');
+
+      equal(controller.active, false);
+      controller.setActive(true);
+      equal(controller.active, true);
+
+      throws(function() {
+        controller.setActive('shenanigans');
+      }, Error, 'setActive can only take a boolean');
+    });
+
+    /**
+     *
+     * Test the resize method.
+     *
+     */
+    test('Test the resize method', function() {
+
+      var container = $('<div id="does-not-exist"></div>');
+      var controller = new EmperorViewControllerABC(container, 'foo', 'bar');
+
+      // header of size 0
+      controller.resize(20, 10);
+      equal(controller.$header.height(), 0);
+      equal(controller.$header.width(), 10); // because of padding
+      equal(controller.$body.height(), 10);
+      equal(controller.$body.width(), 10); // because of padding
+
+      controller.$header.height(11);
+      controller.resize(30, 30);
+      equal(controller.$header.height(), 11);
+      equal(controller.$header.width(), 20); //because of padding
+      equal(controller.$body.height(), 19);
+      equal(controller.$body.width(), 20); //because of padding
+    });
+
+    /**
+     *
+     * Test the resize, toJSON and fromJSON methods raise the appropriate
+     * errors.
+     *
+     */
+    test('Test resize, toJSON and fromJSON methods', function() {
+
+      var container = $('<div id="does-not-exist"></div>');
+      var controller = new EmperorViewControllerABC(container, 'foo', 'bar');
+
+      throws(function() {
+        controller.fromJSON('{foo:11}');
+      }, Error, 'Cannot call this abstract method');
+
+      throws(function() {
+        controller.toJSON();
+      }, Error, 'Cannot call this abstract method');
+    });
+
+    module('EmperorViewController', {
+
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+        metadata = [['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.pcoa = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+        this.decomp = decomp;
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        this.decomp = undefined;
+      }
+    });
+
+    /**
+     *
+     * Test the constructor for EmperorViewController.
+     *
+     */
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="does-not-exist"></div>');
+
+      // verify the subclassing was set properly
+      assert.ok(EmperorViewController.prototype instanceof
+                EmperorViewControllerABC);
+      var attr = new EmperorViewController(container, 'foo', 'bar',
+          this.sharedDecompositionViewDict);
+      equal(attr.activeViewKey, 'pcoa');
+    });
+
+    /**
+     *
+     * Tests to make sure the exceptions are being raised as expected
+     *
+     */
+    test('Constructor test exceptions', function(assert) {
+      var dv = new DecompositionView(this.decomp);
+
+      throws(function() {
+        new EmperorViewController(container, 'foo', 'bar',
+            {1: 1, 2: 2}, {});
+
+      }, Error, 'The decomposition view dictionary ' +
+      'can only have decomposition views');
+
+      throws(function() {
+        new EmperorViewController(container, 'foo', 'bar',
+            {}, {});
+      }, Error, 'The decomposition view dictionary cannot be empty');
+    });
+
+    /**
+     *
+     * Test get active decomposition view key
+     *
+     */
+    test('Test getActiveDecompViewKey', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorViewController(container, 'foo', 'bar',
+                                           {'scatter': dv});
+      equal(attr.getActiveDecompViewKey(), 'scatter');
+    });
+
+    /**
+     *
+     * Test get active decomposition view key
+     *
+     */
+    test('Test getActiveDecompViewKey exception', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorViewController(container, 'foo', 'bar',
+                                           {'scatter': dv});
+      throws(function() {
+        attr.setActiveDecompViewKey('KeyMcKeyFace');
+      }, Error, 'This key is not presen in the dictionary');
+    });
+
+    /**
+     *
+     * Test the active decomposition view can be correctly retrieved
+     *
+     */
+    test('Test getActiveView', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorViewController(container, 'foo', 'bar',
+                                           {'scatter': dv});
+      deepEqual(attr.getActiveView(), dv);
+    });
+
+    /**
+     *
+     * Test set active decomposition view key
+     *
+     */
+    test('Test setActiveDecompViewKey', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorViewController(container, 'foo', 'bar',
+          {'scatter': dv, 'biplot': dv});
+      equal(attr.getActiveDecompViewKey(), 'scatter');
+      attr.setActiveDecompViewKey('biplot');
+      equal(attr.getActiveDecompViewKey(), 'biplot');
+    });
+
+    module('EmperorAttributeABC', {
+
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+        var $slickid = $('<div id="fooligans"></div>');
+        $slickid.appendTo(document.body);
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+        metadata = [['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.pcoa = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        decomp = new DecompositionModel(name, ids, coords, pct_var, md_headers,
+            metadata);
+        dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.biplot = dv;
+
+        // Slickgrid
+        var columns = [
+        {id: 'pc1', name: 'pc1', field: 'pc1'},
+        {id: 'pc2', name: 'pc2', field: 'pc2'},
+        {id: 'pc3', name: 'pc3', field: 'pc3'}
+        ];
+
+        this.options = {
+          enableCellNavigation: true,
+          enableColumnReorder: false
+        };
+        var data = [];
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 1});
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 2});
+
+        grid = new Slick.Grid('#fooligans', data, columns, this.options);
+        this.decomp = decomp;
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        $('#fooligans').remove();
+        this.decomp = undefined;
+      }
+    });
+
+    /**
+     *
+     * Test the constructor for EmperorViewControllerABC.
+     *
+     */
+    test('Constructor tests', function(assert) {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+
+      // verify the subclassing was set properly
+      assert.ok(EmperorAttributeABC.prototype instanceof
+                EmperorViewController);
+      var attr = new EmperorAttributeABC(container, 'foo', 'bar',
+          this.sharedDecompositionViewDict, {});
+    });
+
+    /**
+     *
+     * Test to see if the grid is being built correctly
+     *
+     */
+    asyncTest('Constructor test buildGrid', function(assert) {
+      var options = {};
+      options.slickGridColumn = {id: 'title', name: 'spam', field: 'test',
+        sortable: false, maxWidth: 10, minWidth: 10};
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorAttributeABC(container, 'foo', 'bar',
+          this.sharedDecompositionViewDict,
+          options);
+
+      $(function() {
+        var testColumn = attr.bodyGrid.getColumns()[0];
+        equal(testColumn.name, 'spam');
+        equal(testColumn.field, 'test');
+
+        start(); // qunit
+      });
+    });
+
+    /**
+     *
+     * Test to see if the grid is being built correctly
+     *
+     */
+    asyncTest('Test resize', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist" style="height:20px; ' +
+                        'width:21px"></div>');
+
+      // verify the subclassing was set properly
+      var attr = new EmperorAttributeABC(container, 'foo', 'bar',
+          this.sharedDecompositionViewDict, {});
+
+      $(function() {
+        attr.resize(20, 30);
+        equal(attr.$body.width(), 10); // because of padding
+        equal(attr.$body.height(), 30 - attr.$header.height());
+        equal(attr.$header.width(), 10); // because of padding
+
+        start(); // qunit
+      });
+    });
+
+    /**
+     *
+     * Test set metadata field
+     *
+     */
+    test('Test setMetadataField', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorAttributeABC(container, 'foo', 'bar',
+          {'scatter': dv}, {});
+      attr.setMetadataField('cheese');
+      equal(attr.metadataField, 'cheese');
+    });
+
+    /**
+     *
+     * Test get/set slick grid dataset.
+     *
+     */
+    asyncTest('Test setSlickGridDataset', function() {
+      var dv = new DecompositionView(this.decomp);
+      var container = $('<div id="does-not-exist"></div>');
+      var attr = new EmperorAttributeABC(container, 'foo', 'bar',
+          {'scatter': dv, 'biplot': dv}, {});
+
+      $(function() {
+        attr.setSlickGridDataset([{'pc1': 1, 'pc2': 2, 'pc3': 3},
+            {'pc1': 1, 'pc2': 1, 'pc3': 2}]);
+        deepEqual(attr.getSlickGridDataset(), [{'pc1': 1, 'pc2': 2, 'pc3': 3},
+            {'pc1': 1, 'pc2': 1, 'pc3': 2}]);
+
+        start(); // qunit
+      });
+    });
+  });
+});
diff --git a/tests/javascript_tests/test_visibility_controller.js b/tests/javascript_tests/test_visibility_controller.js
new file mode 100644
index 0000000..caa2ffc
--- /dev/null
+++ b/tests/javascript_tests/test_visibility_controller.js
@@ -0,0 +1,145 @@
+requirejs([
+    'jquery',
+    'underscore',
+    'model',
+    'view',
+    'viewcontroller',
+    'slickgrid',
+    'visibilitycontroller'
+], function($, _, model, DecompositionView, viewcontroller, SlickGrid,
+            VisibilityController) {
+  $(document).ready(function() {
+    var EmperorAttributeABC = viewcontroller.EmperorAttributeABC;
+    var DecompositionModel = model.DecompositionModel;
+
+    module('VisibilityController', {
+      setup: function() {
+        this.sharedDecompositionViewDict = {};
+        var $slickid = $('<div id="fooligans"></div>');
+        $slickid.appendTo(document.body);
+
+        // setup function
+        name = 'pcoa';
+        ids = ['PC.636', 'PC.635'];
+        coords = [
+          [-0.276542, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'LinkerPrimerSequence', 'Treatment', 'DOB'];
+        metadata = [['PC.636', 'YATGCTGCCTCCCGTAGGAGT', 'Control', '20070314'],
+        ['PC.635', 'YATGCTGCCTCCCGTAGGAGT', 'Fast', '20071112']];
+        var decomp = new DecompositionModel(name, ids, coords, pct_var,
+                                            md_headers, metadata);
+        var dv = new DecompositionView(decomp);
+        this.sharedDecompositionViewDict.scatter = dv;
+
+        name = 'biplot';
+        ids = ['tax_1', 'tax_2'];
+        coords = [
+          [-1, -0.144964, 0.066647, -0.067711, 0.176070, 0.072969,
+          -0.229889, -0.046599],
+          [-0.237661, 0.046053, -0.138136, 0.159061, -0.247485, -0.115211,
+          -0.112864, 0.064794]];
+        pct_var = [26.6887048633, 16.2563704022, 13.7754129161, 11.217215823,
+        10.024774995, 8.22835130237, 7.55971173665, 6.24945796136];
+        md_headers = ['SampleID', 'Gram'];
+        metadata = [['tax_1', '1'],
+        ['tax_2', '0']];
+        this.decomp = new DecompositionModel(name, ids, coords, pct_var,
+                                             md_headers, metadata);
+        this.dv = new DecompositionView(this.decomp);
+        this.sharedDecompositionViewDict.biplot = this.dv;
+
+        // Slickgrid
+        var columns = [
+        {id: 'pc1', name: 'pc1', field: 'pc1'},
+        {id: 'pc2', name: 'pc2', field: 'pc2'},
+        {id: 'pc3', name: 'pc3', field: 'pc3'}
+        ];
+
+        var options = {
+          enableCellNavigation: true,
+          enableColumnReorder: false
+        };
+        var data = [];
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 1});
+        data.push({'pc1': 1, 'pc2': 1, 'pc3': 2});
+
+        grid = new Slick.Grid('#fooligans', data, columns, options);
+      },
+      teardown: function() {
+        this.sharedDecompositionViewDict = undefined;
+        $('#fooligans').remove();
+        this.decomp = undefined;
+      }
+    });
+
+    test('Constructor tests', function(assert) {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+
+      assert.ok(VisibilityController.prototype instanceof EmperorAttributeABC);
+
+      var controller = new VisibilityController(container,
+          this.sharedDecompositionViewDict);
+      equal(controller.title, 'Visibility');
+
+      var testColumn = controller.bodyGrid.getColumns()[0];
+      equal(testColumn.field, 'value');
+
+      // verify the visibility value is set properly
+      equal(controller.$select.val(), 'SampleID');
+    });
+
+    test('Testing setPlottableAttributes helper function', function(assert) {
+      // testing with one plottable
+      var idx = 0;
+      plottables = [{idx: idx}];
+      equal(this.dv.markers[idx].visible, true);
+      equal(this.dv.markers[idx + 1].visible, true);
+      VisibilityController.prototype.setPlottableAttributes(this.dv, false,
+                                                            plottables);
+      equal(this.dv.needsUpdate, true);
+
+      // testing with multiple plottable
+      plottables = [{idx: idx}, {idx: idx + 1}];
+      equal(this.dv.markers[idx].visible, false);
+      equal(this.dv.markers[idx + 1].visible, true);
+      VisibilityController.prototype.setPlottableAttributes(this.dv, true,
+                                                            plottables);
+      equal(this.dv.markers[idx].visible, true);
+      equal(this.dv.markers[idx + 1].visible, true);
+      equal(this.dv.needsUpdate, true);
+    });
+
+    test('Testing toJSON', function() {
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new VisibilityController(container,
+          this.sharedDecompositionViewDict);
+
+      var obs = controller.toJSON();
+      var exp = {category: 'SampleID', data: {'PC.636': true, 'PC.635': true}};
+      deepEqual(obs, exp);
+    });
+
+    test('Testing fromJSON', function() {
+      var json = {category: 'SampleID',
+                  data: {'PC.636': false, 'PC.635': true}};
+      var container = $('<div id="does-not-exist" style="height:11px; ' +
+                        'width:12px"></div>');
+      var controller = new VisibilityController(container,
+          this.sharedDecompositionViewDict);
+      controller.fromJSON(json);
+
+      var idx = 0;
+      equal(controller.decompViewDict.scatter.markers[idx].visible, false);
+      equal(controller.decompViewDict.scatter.markers[idx + 1].visible, true);
+    });
+
+  });
+
+});
diff --git a/tests/scripts_test_data/make_emperor/euclidian_pc.txt b/tests/scripts_test_data/make_emperor/euclidian_pc.txt
new file mode 100644
index 0000000..4c0ab8a
--- /dev/null
+++ b/tests/scripts_test_data/make_emperor/euclidian_pc.txt
@@ -0,0 +1,22 @@
+Eigvals	9
+2113.87769515	1393.78422506	1286.1278607	721.583201647	619.243592932	403.820943293	338.646139111	234.249675441	3.51088839931e-14
+
+Proportion explained	9
+29.725476167	19.5994781812	18.0856078658	10.1469466811	8.70784090557	5.67855456023	4.76206251679	3.29403312235	4.93703252927e-16
+
+Species	0	0
+
+Site	9	9
+PC.636	-331145.20264	-28746.172411	176651.92951	41131.181799	-45045.127106	31002.999302	15436.982784	-28438.633732	62457.826918e-08
+PC.635	-05865.46432	-00673.7346284	-09690.1359226	-54964.525082	33969.654445	-46668.082581	-47392.730972	123809.32806	62457.826918e-08
+PC.356	17975.11616	32848.336186	73517.801894	05207.7997723	-08972.2011337	-38306.909293	-144036.21724	-53598.317151	62457.826918e-08
+PC.481	3960.409524	08002.8177751	-48184.576843	-76898.730039	-124485.9918	-121756.07879	68411.120232	-24870.225958	62457.826918e-08
+PC.354	9352.88298	122179.94651	200955.98811	-19671.13805	56372.190756	34940.192279	68035.029983	19707.122884	62457.826918e-08
+PC.593	15339.92756	-256057.84595	-21921.249063	150300.00954	11447.521475	-09272.1500336	21843.731811	14536.86064	62457.826918e-08
+PC.355	2968.389343	163095.24329	-151119.74079	86885.971443	-109333.07682	89789.760226	-07866.6773017	20757.853304	62457.826918e-08
+PC.607	1173.196508	-141750.86794	-81477.081894	-171512.86387	20240.125844	100012.98839	-02365.1798391	-26452.945905	62457.826918e-08
+PC.634	02759.25512	101102.17718	-138732.93501	39522.594488	165806.70434	-39742.519496	27933.840546	-45451.04214	62457.826918e-08
+
+Biplot	0	0
+
+Site constraints	0	0
diff --git a/tests/test_core.py b/tests/test_core.py
new file mode 100644
index 0000000..9312368
--- /dev/null
+++ b/tests/test_core.py
@@ -0,0 +1,152 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+from unittest import TestCase, main
+from os.path import exists
+from shutil import rmtree
+from io import StringIO
+from skbio import OrdinationResults
+
+import pandas as pd
+import numpy as np
+
+from emperor.core import Emperor
+
+# account for what's allowed in python 2 vs PY3K
+try:
+    from . import _test_core_strings as tcs
+except:
+    import _test_core_strings as tcs
+
+
+class TopLevelTests(TestCase):
+    def setUp(self):
+        or_f = StringIO(tcs.PCOA_STRING)
+        self.ord_res = OrdinationResults.read(or_f)
+
+        data = \
+            [['PC.354', 'Control', '20061218', 'Ctrol_mouse_I.D._354'],
+             ['PC.355', 'Control', '20061218', 'Control_mouse_I.D._355'],
+             ['PC.356', 'Control', '20061126', 'Control_mouse_I.D._356'],
+             ['PC.481', 'Control', '20070314', 'Control_mouse_I.D._481'],
+             ['PC.593', 'Control', '20071210', 'Control_mouse_I.D._593'],
+             ['PC.607', 'Fast', '20071112', 'Fasting_mouse_I.D._607'],
+             ['PC.634', 'Fast', '20080116', 'Fasting_mouse_I.D._634'],
+             ['PC.635', 'Fast', '20080116', 'Fasting_mouse_I.D._635'],
+             ['PC.636', 'Fast', '20080116', 'Fasting_mouse_I.D._636']]
+        headers = ['SampleID', 'Treatment', 'DOB', 'Description']
+        self.mf = pd.DataFrame(data=data, columns=headers)
+        self.mf.set_index('SampleID', inplace=True)
+        self.files_to_remove = []
+
+        np.random.seed(111)
+
+    def tearDown(self):
+        for path in self.files_to_remove:
+            if exists(path):
+                rmtree(path)
+
+    def test_str(self):
+        emp = Emperor(self.ord_res, self.mf)
+        self.assertEqual(emp.base_url, 'https://cdn.rawgit.com/biocore/emperor'
+                                       '/new-api/emperor/support_files')
+
+        obs = str(emp)
+
+        try:
+            self.assertItemsEqual(tcs.HTML_STRING.split('\n'), obs.split('\n'))
+        except AttributeError:
+            self.assertCountEqual(tcs.HTML_STRING.split('\n'), obs.split('\n'))
+        self.assertEqual(tcs.HTML_STRING, obs)
+
+    def test_remote_url(self):
+        emp = Emperor(self.ord_res, self.mf, remote=False)
+        self.assertEqual(emp.base_url, "/nbextensions/emperor/support_files")
+
+    def test_remote_url_custom(self):
+        emp = Emperor(self.ord_res, self.mf, remote='/foobersurus/bar/')
+        self.assertEqual(emp.base_url, '/foobersurus/bar/')
+
+    def test_unnamed_index(self):
+        self.mf.index.name = None
+        emp = Emperor(self.ord_res, self.mf)
+        obs = str(emp)
+
+        try:
+            self.assertItemsEqual(tcs.HTML_STRING.split('\n'), obs.split('\n'))
+        except AttributeError:
+            self.assertCountEqual(tcs.HTML_STRING.split('\n'), obs.split('\n'))
+
+        self.assertEqual(tcs.HTML_STRING, obs)
+
+    def test_standalone(self):
+        local_path = './some-local-path/'
+
+        emp = Emperor(self.ord_res, self.mf, remote=local_path)
+        self.assertEqual(emp.base_url, local_path)
+
+        obs = emp.make_emperor(standalone=True)
+
+        try:
+            self.assertItemsEqual(tcs.STANDALONE_HTML_STRING.split('\n'),
+                                  obs.split('\n'))
+        except AttributeError:
+            self.assertCountEqual(tcs.STANDALONE_HTML_STRING.split('\n'),
+                                  obs.split('\n'))
+        self.assertEqual(tcs.STANDALONE_HTML_STRING, obs)
+
+    def test_copy_support_files_use_base(self):
+        local_path = './some-local-path/'
+
+        emp = Emperor(self.ord_res, self.mf, remote=local_path)
+        self.assertEqual(emp.base_url, local_path)
+
+        emp.copy_support_files()
+
+        self.assertTrue(exists(local_path))
+
+        self.files_to_remove.append(local_path)
+
+    def test_copy_support_files_use_target(self):
+        local_path = './some-local-path/'
+
+        emp = Emperor(self.ord_res, self.mf, remote=local_path)
+        self.assertEqual(emp.base_url, local_path)
+
+        emp.copy_support_files(target='./something-else')
+
+        self.assertTrue(exists('./something-else'))
+
+        self.files_to_remove.append(local_path)
+        self.files_to_remove.append('./something-else')
+
+    def test_custom_axes(self):
+        emp = Emperor(self.ord_res, self.mf)
+        obs = emp.make_emperor(custom_axes=['DOB'])
+
+        with open('test.txt', 'w') as f:
+            f.write(obs)
+
+        try:
+            self.assertItemsEqual(tcs.HTML_STRING_CUSTOM_AXES.split('\n'),
+                                  obs.split('\n'))
+        except AttributeError:
+            self.assertCountEqual(tcs.HTML_STRING_CUSTOM_AXES.split('\n'),
+                                  obs.split('\n'))
+        self.assertEqual(tcs.HTML_STRING_CUSTOM_AXES, obs)
+
+    def test_custom_axes_missing_headers(self):
+        emp = Emperor(self.ord_res, self.mf)
+
+        with self.assertRaises(KeyError):
+            emp.make_emperor(custom_axes=[':L'])
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/test_data/.some-hidden-file b/tests/test_data/.some-hidden-file
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/dir-with-only-hidden-files/.1.txt b/tests/test_data/dir-with-only-hidden-files/.1.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/dir-with-only-hidden-files/.2.txt b/tests/test_data/dir-with-only-hidden-files/.2.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/dir-with-only-hidden-files/.3.txt b/tests/test_data/dir-with-only-hidden-files/.3.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/dir-with-only-hidden-files/.4.txt b/tests/test_data/dir-with-only-hidden-files/.4.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/procrustes_results.txt b/tests/test_data/procrustes_results.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/unweighted_unifrac_pc_transformed_reference.txt b/tests/test_data/unweighted_unifrac_pc_transformed_reference.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_data/weighted_unifrac_pc_transformed_q1.txt b/tests/test_data/weighted_unifrac_pc_transformed_q1.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_pandas.py b/tests/test_pandas.py
new file mode 100644
index 0000000..bf4878e
--- /dev/null
+++ b/tests/test_pandas.py
@@ -0,0 +1,105 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+from unittest import TestCase, main
+
+import pandas as pd
+import numpy as np
+
+from emperor.core import Emperor
+from emperor._pandas import scatterplot
+
+# account for what's allowed in python 2 vs PY3K
+try:
+    from . import _test_core_strings as tcs
+except:
+    import _test_core_strings as tcs
+
+# from http://stackoverflow.com/a/22605281/379593
+import sys
+if sys.version_info[0] < 3:
+    from StringIO import StringIO
+else:
+    from io import StringIO
+
+
+class TopLevelTests(TestCase):
+    def setUp(self):
+        self.df = pd.read_csv(StringIO(tcs.MAP_PANDAS), sep='\t',
+                              index_col='#SampleID')
+
+        x = np.array([[0.27272727, 0.65384615, 1., 0.24657534],
+                      [0.03896104, 0.46153846, 0.58666667, 0.57534247],
+                      [0.68831169, 1., 0.06666667, 0.95890411],
+                      [0.61038961, 0.92307692, 0.96, 0.17808219],
+                      [0.16883117, 0.71794872, 0.01333333, 0.68493151],
+                      [0.16883117, 0.06410256, 0.52, 0.76712329],
+                      [1., 0.82051282, 0.34666667, 0.23287671],
+                      [0.81818182, 0.88461538, 0.98666667, 0.2739726],
+                      [0.25974026, 0.20512821, 0.52, 0.43835616],
+                      [0.24675325, 0.21794872, 0.81333333, 0.60273973],
+                      [0.61038961, 0.53846154, 0.49333333, 0.34246575],
+                      [0.64935065, 0.74358974, 0.36, 1.],
+                      [0.14285714, 0.41025641, 0.54666667, 0.49315068],
+                      [0.11688312, 0.32051282, 0.56, 0.43835616]])
+        ind = pd.Index(['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9',
+                        's10', 's11', 's12', 's13', 's14'], dtype='object',
+                       name='#SampleID')
+        cols = pd.Index(['num_1', 'num_4', 'num_3', 'num_2'], dtype='object')
+        self.samples = pd.DataFrame(data=x, index=ind, columns=cols)
+
+    def test_scatterplot(self):
+        emp = scatterplot(self.df)
+
+        self.assertTrue(isinstance(emp, Emperor))
+        self.assertEqual(emp.dimensions, 4)
+        self.assertEqual(emp.base_url, 'https://cdn.rawgit.com/biocore/'
+                         'emperor/new-api/emperor/support_files')
+
+        pd.util.testing.assert_frame_equal(self.df, emp.mf)
+
+        pd.util.testing.assert_frame_equal(emp.ordination.samples,
+                                           self.samples)
+
+    def test_scatterplot_reordered(self):
+        emp = scatterplot(self.df, x='num_3', y='num_2', z='num_1')
+
+        self.assertTrue(isinstance(emp, Emperor))
+        self.assertEqual(emp.dimensions, 4)
+        self.assertEqual(emp.base_url, 'https://cdn.rawgit.com/biocore/'
+                         'emperor/new-api/emperor/support_files')
+
+        pd.util.testing.assert_frame_equal(self.df, emp.mf)
+
+        reordered = self.samples[['num_3', 'num_2', 'num_1', 'num_4']].copy()
+
+        pd.util.testing.assert_frame_equal(emp.ordination.samples,
+                                           reordered)
+
+    def test_bad_column_names(self):
+        np.testing.assert_raises(ValueError, scatterplot, self.df, x=':L')
+        np.testing.assert_raises(ValueError, scatterplot, self.df, x='num_1',
+                                 y='column', z='McColumnFace')
+
+    def test_bad_data(self):
+        no_numeric = self.df.select_dtypes(include=['object']).copy()
+
+        np.testing.assert_raises(ValueError, scatterplot, no_numeric)
+
+    def test_bad_non_numeric_columns(self):
+        np.testing.assert_raises(ValueError, scatterplot, self.df, x='cat_a')
+
+    def test_no_dataframe(self):
+        np.testing.assert_raises(ValueError, scatterplot, None)
+        np.testing.assert_raises(ValueError, scatterplot, 1)
+        np.testing.assert_raises(ValueError, scatterplot, 'DataMcDataface')
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/test_parse.py b/tests/test_parse.py
new file mode 100644
index 0000000..3ce801c
--- /dev/null
+++ b/tests/test_parse.py
@@ -0,0 +1,106 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, emperor development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE.md, distributed with this software.
+# ----------------------------------------------------------------------------
+from __future__ import division
+
+from unittest import TestCase, main
+from tempfile import mkstemp
+from os import close
+try:
+    from StringIO import StringIO
+except:
+    from io import StringIO
+
+import numpy as np
+import numpy.testing as npt
+
+from emperor.parse import parse_coords
+
+
+class ParseTests(TestCase):
+
+    def test_parse_coords_ordination_results(self):
+        """parse_coords should handle skbio's OrdinationResults file"""
+        coords = StringIO(ordination_results_file)
+
+        obs = parse_coords(coords)
+        exp = (['A', 'B', 'C'],
+               np.array([[.11, .09, .23], [.03, .07, -.26], [.12, .06, -.32]]),
+               np.array([4.94, 1.79, 1.50]),
+               np.array([14.3, 5.2, 4.3]))
+        # test the header and the values apart from each other
+        self.assertEqual(obs[0], exp[0])
+        npt.assert_almost_equal(obs[1], exp[1])
+        npt.assert_almost_equal(obs[2], exp[2])
+        npt.assert_almost_equal(obs[3], exp[3])
+
+    def test_parse_coords_qiime(self):
+        """parse_coords should handle old qiime PCoA coords format"""
+        coords = StringIO(qiime_pcoa_file)
+        obs = parse_coords(coords)
+        exp = (['A', 'B', 'C'],
+               np.array([[.11, .09, .23], [.03, .07, -.26], [.12, .06, -.32]]),
+               np.array([4.94, 1.79, 1.50]),
+               np.array([14.3, 5.2, 4.3]))
+        # test the header and the values apart from each other
+        self.assertEqual(obs[0], exp[0])
+        npt.assert_almost_equal(obs[1], exp[1])
+        npt.assert_almost_equal(obs[2], exp[2])
+        npt.assert_almost_equal(obs[3], exp[3])
+
+    def test_parse_coords_qiime_file(self):
+        """parse_coords should handle old qiime PCoA coords file"""
+        fd, fp = mkstemp()
+        close(fd)
+
+        with open(fp, 'w') as f:
+            f.write(qiime_pcoa_file)
+
+        with open(fp, 'r') as f:
+            obs = parse_coords(f)
+
+        exp = (['A', 'B', 'C'],
+               np.array([[.11, .09, .23], [.03, .07, -.26], [.12, .06, -.32]]),
+               np.array([4.94, 1.79, 1.50]),
+               np.array([14.3, 5.2, 4.3]))
+        # test the header and the values apart from each other
+        self.assertEqual(obs[0], exp[0])
+        npt.assert_almost_equal(obs[1], exp[1])
+        npt.assert_almost_equal(obs[2], exp[2])
+        npt.assert_almost_equal(obs[3], exp[3])
+
+ordination_results_file = u"""Eigvals\t3
+4.94\t1.79\t1.50
+
+Proportion explained\t3
+14.3\t5.2\t4.3
+
+Species\t0\t0
+
+Site\t3\t3
+A\t.11\t.09\t.23
+B\t.03\t.07\t-.26
+C\t.12\t.06\t-.32
+
+Biplot\t0\t0
+
+Site constraints\t0\t0"""
+
+qiime_pcoa_file = """pc vector number\t1\t2\t3
+A\t0.11\t0.09\t0.23
+B\t0.03\t0.07\t-0.26
+C\t0.12\t0.06\t-0.32
+
+
+eigvals\t4.94\t1.79\t1.50
+% variation explained\t14.3\t5.2\t4.3
+
+
+"""
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/test_pycogent_backports/test_procrustes.py b/tests/test_pycogent_backports/test_procrustes.py
deleted file mode 100755
index cbc99e8..0000000
--- a/tests/test_pycogent_backports/test_procrustes.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env python
-
-from unittest import main, TestCase
-from numpy import (array, sqrt, dot, trace, transpose, pi, cos, sin, dot, trace,
-    append)
-from numpy.testing import assert_almost_equal
-from emperor.pycogent_backports.procrustes import (procrustes, get_disparity,
-    center, normalize)
-
-
-__author__ = "Justin Kuczynski"
-__copyright__ = "Copyright 2007-2012, The Cogent Project"
-__credits__ = ["Justin Kuczynski"]
-__license__ = "BSD"
-__version__ = "1.5.3-dev"
-__maintainer__ = "Justin Kuczynski"
-__email__ = "justinak at gmail.com"
-__status__ = "Production"
-
-class procrustesTests(TestCase):
-    """test the procrustes module, using floating point numpy arrays
-    """
-
-    def setUp(self):
-        """creates inputs"""
-        # an L
-        self.data1 = array([[1, 3],
-                    [1, 2],
-                    [1, 1],
-                    [2, 1]], 'd')
-            
-        # a larger, shifted, mirrored L
-        self.data2 = array([[4, -2],
-                    [4, -4],
-                    [4, -6],
-                    [2, -6]], 'd') 
-                    
-        # an L shifted up 1, right 1, and with point 4 shifted an extra .5
-        # to the right
-        # pointwise distance disparity with data1: 3*(2) + (1 + 1.5^2)
-        self.data3 = array([[2, 4],
-                    [2, 3],
-                    [2, 2],
-                    [3, 2.5]], 'd')
-                    
-        # data4, data5 are standardized (trace(A*A') = 1).
-        # procrustes should return an identical copy if they are used
-        # as the first matrix argument.
-        shiftangle = pi/8
-        self.data4 = array([[1,0],
-                            [0,1],
-                            [-1,0],
-                            [0,-1]],'d')/sqrt(4)
-        self.data5 = array([[cos(shiftangle), sin(shiftangle)],
-                            [cos(pi/2-shiftangle), sin(pi/2-shiftangle)],
-                            [-cos(shiftangle), -sin(shiftangle)],
-                            [-cos(pi/2-shiftangle), -sin(pi/2-shiftangle)]],
-                            'd')/sqrt(4)
-                        
-                        
-    def test_procrustes(self):
-        """tests procrustes' ability to match two matrices.
-        
-        the second matrix is a rotated, shifted, scaled, and mirrored version
-        of the first, in two dimensions only
-        """
-        # can shift, mirror, and scale an 'L'?
-        a,b,disparity = procrustes(self.data1, self.data2)
-        assert_almost_equal(b, a)
-        assert_almost_equal(disparity,0.)
-        
-        # if first mtx is standardized, leaves first mtx unchanged?
-        m4, m5, disp45 = procrustes(self.data4, self.data5)
-        assert_almost_equal(m4, self.data4)
-
-        # at worst, data3 is an 'L' with one point off by .5
-        m1, m3, disp13 = procrustes(self.data1, self.data3)
-        self.assertTrue(disp13 < .5**2)
-        
-    def test_procrustes2(self):
-        """procrustes disparity should not depend on order of matrices"""
-        m1, m3, disp13 = procrustes(self.data1, self.data3)
-        m3_2, m1_2, disp31 = procrustes(self.data3, self.data1)
-        assert_almost_equal(disp13, disp31)
-        
-        # try with 3d, 8 pts per
-        rand1 = array([[ 2.61955202,  0.30522265,  0.55515826],
-        [ 0.41124708, -0.03966978, -0.31854548],
-        [ 0.91910318,  1.39451809, -0.15295084],
-        [ 2.00452023,  0.50150048,  0.29485268],
-        [ 0.09453595,  0.67528885,  0.03283872],
-        [ 0.07015232,  2.18892599, -1.67266852],
-        [ 0.65029688,  1.60551637,  0.80013549],
-        [-0.6607528 ,  0.53644208,  0.17033891]])
-        
-        rand3 = array([[ 0.0809969 ,  0.09731461, -0.173442  ],
-        [-1.84888465, -0.92589646, -1.29335743],
-        [ 0.67031855, -1.35957463,  0.41938621],
-        [ 0.73967209, -0.20230757,  0.52418027],
-        [ 0.17752796,  0.09065607,  0.29827466],
-        [ 0.47999368, -0.88455717, -0.57547934],
-        [-0.11486344, -0.12608506, -0.3395779 ],
-        [-0.86106154, -0.28687488,  0.9644429 ]])
-        res1, res3, disp13 = procrustes(rand1,rand3)
-        res3_2, res1_2, disp31 = procrustes(rand3, rand1)
-        assert_almost_equal(disp13, disp31)
-        
-    def test_get_disparity(self):
-        """tests get_disparity"""
-        disp = get_disparity(self.data1, self.data3)
-        disp2 = get_disparity(self.data3, self.data1)
-        assert_almost_equal(disp, disp2)
-        assert_almost_equal(disp, (3.*2. + (1. + 1.5**2)))
-        
-        d1 = append(self.data1, self.data1, 0)
-        d3 = append(self.data3, self.data3, 0)
-        
-        disp3 = get_disparity(d1,d3)
-        disp4 = get_disparity(d3,d1)
-        assert_almost_equal(disp3, disp4)
-        # 2x points in same configuration should give 2x disparity
-        assert_almost_equal(disp3, 2.*disp)
-        
-    def test_center(self):
-        centered_mtx = center(self.data1)
-        column_means = centered_mtx.mean(0)
-        for col_mean in column_means:
-            assert_almost_equal(col_mean, 0.)
-            
-    def test_normalize(self):
-        norm_mtx = normalize(self.data1)
-        assert_almost_equal(trace(dot(norm_mtx,transpose(norm_mtx))), 1.)
-        
-    # match_points isn't yet tested, as it's almost a private function
-    # and test_procrustes() tests it implicitly.
-        
-#run if called from command line
-if __name__ == '__main__':
-       main()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/emperor.git



More information about the debian-med-commit mailing list